国产精品chinese,色综合天天综合精品网国产在线,成午夜免费视频在线观看,清纯女学生被强行糟蹋小说

    <td id="ojr13"><tr id="ojr13"><label id="ojr13"></label></tr></td>
        • <source id="ojr13"></source>
            <td id="ojr13"><ins id="ojr13"><label id="ojr13"></label></ins></td>

            Article / 文章中心

            優(yōu)化托管于阿里云函數(shù)計(jì)算的Node.js應(yīng)用 - 以Parse為例

            發(fā)布時(shí)間:2022-02-22 點(diǎn)擊數(shù):862

            上文介紹了怎么快速搬遷Parse到阿里云函數(shù)核算,可是這只是一個(gè)跑起來(lái)的比如,還有一些問(wèn)題需求咱們優(yōu)化。本文會(huì)介紹常見(jiàn)的優(yōu)化點(diǎn)和辦法,從辦法來(lái)看適用于一切Serverless渠道的應(yīng)用。

            Serverless的缺陷

            沒(méi)有任何技能形狀是完美的,Serverless供給了杰出的可伸縮性和并發(fā)性,供給了細(xì)粒度的資源分配,優(yōu)化了成本,相對(duì)的也有難以調(diào)試等缺點(diǎn)。

            這些問(wèn)題是Serverless這種技能形狀本身形成的,并不是阿里云函數(shù)核算獨(dú)有的。不同的云廠商能夠經(jīng)過(guò)周邊建設(shè)來(lái)補(bǔ)償一些問(wèn)題,比如阿里云函數(shù)核算的日志和監(jiān)控相對(duì)比較完善,Serverless Devs工具處理了一部分調(diào)試問(wèn)題。

            用更傳統(tǒng)的觀點(diǎn)來(lái)了解Serverless的本質(zhì),能夠看作擴(kuò)容縮容戰(zhàn)略極端激進(jìn)的集群,而每個(gè)函數(shù)都是布置在這一個(gè)一個(gè)機(jī)器上罷了。云廠商的機(jī)器特別迷你,計(jì)價(jià)單位顆粒小。而縮容戰(zhàn)略能夠?qū)?,擴(kuò)容戰(zhàn)略能夠近乎無(wú)限大,縮容戰(zhàn)略是固定,不能夠自定義。

            那么對(duì)于一個(gè)隨時(shí)可能創(chuàng)建隨時(shí)可能被毀掉的機(jī)器,布置于其間的服務(wù)要面臨兩個(gè)方面的問(wèn)題

            • 服務(wù)毀掉
            • 服務(wù)發(fā)動(dòng)

            服務(wù)毀掉時(shí)內(nèi)存、文件體系的數(shù)據(jù)都丟失了。服務(wù)發(fā)動(dòng)的時(shí)分需求一些必要的初始化,需求發(fā)動(dòng)程序。

            咱們先看下毀掉引起的耐久化問(wèn)題。

            耐久化改善

            Parse是支撐文件上傳的,存儲(chǔ)文件的FileAdapter是能夠自定義的。

            一般來(lái)說(shuō)對(duì)于文件需求,能夠直接運(yùn)用阿里云目標(biāo)存儲(chǔ)OSS,一般挑選標(biāo)準(zhǔn)型就能夠了。


            aliyun-oss-price.png

            Parse官方不支撐阿里云OSS,理論上能夠運(yùn)用parse-server-s3-adapter,可是我之前沒(méi)有配置過(guò),能夠完全能夠自定義,直接運(yùn)用OSS官方的SDK就行了。


            'use strict';  var OSS = require('ali-oss').Wrapper; const DEFAULT_OSS_REGION = "oss-cn-hangzhou";  function requiredOrFromEnvironment(options, key, env) {  options[key] = options[key] || process.env[env];  if (!options[key]) {  throw `OSSAdapter requires option '${key}' or env. variable ${env}`;  }  return options; }  function fromEnvironmentOrDefault(options, key, env, defaultValue) {  options[key] = options[key] || process.env[env] || defaultValue;  return options; }  function optionsFromArguments(args) {  let options = {};  let accessKeyOrOptions = args[0];  if (typeof accessKeyOrOptions == 'string') {  options.accessKey = accessKeyOrOptions;  options.secretKey = args[1];  options.bucket = args[2];  let otherOptions = args[3];  if (otherOptions) {  options.bucketPrefix = otherOptions.bucketPrefix;  options.region = otherOptions.region;  options.directAccess = otherOptions.directAccess;  options.baseUrl = otherOptions.baseUrl;  options.baseUrlDirect = otherOptions.baseUrlDirect;  }  } else {  options = accessKeyOrOptions || {};  }  options = requiredOrFromEnvironment(options, 'accessKey', 'OSS_ACCESS_KEY');  options = requiredOrFromEnvironment(options, 'secretKey', 'OSS_SECRET_KEY');  options = requiredOrFromEnvironment(options, 'bucket', 'OSS_BUCKET');  options = fromEnvironmentOrDefault(options, 'bucketPrefix', 'OSS_BUCKET_PREFIX', '');  options = fromEnvironmentOrDefault(options, 'region', 'OSS_REGION', DEFAULT_OSS_REGION);  options = fromEnvironmentOrDefault(options, 'directAccess', 'OSS_DIRECT_ACCESS', false);  options = fromEnvironmentOrDefault(options, 'baseUrl', 'OSS_BASE_URL', null);  options = fromEnvironmentOrDefault(options, 'baseUrlDirect', 'OSS_BASE_URL_DIRECT', false);   return options; }  function OSSAdapter() {  var options = optionsFromArguments(arguments);  this._region = options.region;  this._bucket = options.bucket;  this._bucketPrefix = options.bucketPrefix;  this._directAccess = options.directAccess;  this._baseUrl = options.baseUrl;  this._baseUrlDirect = options.baseUrlDirect;   let ossOptions = {  accessKeyId: options.accessKey, accessKeySecret: options.secretKey, bucket: this._bucket, region: this._region  };  this._ossClient = new OSS(ossOptions);  this._ossClient.listBuckets().then((val) => {  var bucket = val.buckets.filter((bucket) => {  return bucket.name === this._bucket  }).pop();   this._hasBucket = !!bucket;  }); }  OSSAdapter.prototype.createBucket = function () {  if (this._hasBucket) {  return Promise.resolve();  } else {  return this._ossClient.putBucket(this._bucket, this._region).then(() => {  this._hasBucket = true;  if (this._directAccess) {  return this._ossClient.putBucketACL(this._bucket, this._region, 'public-read');  }  return Promise.resolve();  }).then(() => {  return this._ossClient.useBucket(this._bucket, this._region);  });  } };  OSSAdapter.prototype.createFile = function (filename, data, contentType) {  let options = {};  if (contentType) {  options.headers = {'Content-Type': contentType}  }  return this.createBucket().then(() => {   return this._ossClient.put(this._bucketPrefix + filename, new Buffer(data), options);   }); };  OSSAdapter.prototype.deleteFile = function (filename) {  return this.createBucket().then(() => {  return this._ossClient.delete(this._bucketPrefix + filename);  }); };  OSSAdapter.prototype.getFileData = function (filename) {  return this.createBucket().then(() => {  return this._ossClient.get(this._bucketPrefix + filename).then((val) => {  return Promise.resolve(val.content);  }).catch((err) => {  return Promise.reject(err);  });  }); };  OSSAdapter.prototype.getFileLocation = function (config, filename) {  var url = this._ossClient.signatureUrl(this._bucketPrefix + filename);  url = url.replace(/^http:/, "https:");  return url; };  module.exports = OSSAdapter; module.exports.default = OSSAdapter;

            這個(gè)是我正在用的adapter,能夠參閱運(yùn)用。特別是getFileLocation,要根據(jù)自己情況運(yùn)用。

            Parse還有一個(gè)緩存,一般默許運(yùn)用本地環(huán)境,可是考慮到Serverless的特性,這一部分還是要耐久化用于加快。官方供給的RedisCacheAdapter能夠直接運(yùn)用。Redis集群要求不是很高,最好復(fù)用已有的,單獨(dú)運(yùn)用成本有點(diǎn)高。


            發(fā)動(dòng)改善


            Serverless函數(shù)的生命周期問(wèn)題一直是搬遷的阻止,比較明顯的是異步懇求丟失、高雅下線困難。阿里云函數(shù)核算對(duì)于模型有必定擴(kuò)展,額定供給了一些Hook。


            aliyun-function-model.png


            初始化只會(huì)進(jìn)行一次,preFreeze和preStop便是退出前的Hook,這三處也是同樣的計(jì)費(fèi)。


            因?yàn)镻arse也涉及到數(shù)據(jù)庫(kù)銜接,所以能夠?qū)?shù)據(jù)庫(kù)銜接部分移動(dòng)到initialize中。

            除了生命周期上一般來(lái)說(shuō)還有一些挑選


            提升內(nèi)存分配:函數(shù)核算能夠自行配置內(nèi)存,對(duì)于部分應(yīng)用(特別是有初始化掃描等)加大內(nèi)存能夠改善發(fā)動(dòng)速度


            調(diào)整結(jié)構(gòu)或者渠道:對(duì)于NodeJs而言,新版別普遍都有性能上的優(yōu)化,選用盡可能新的NodeJs版別也能夠加快發(fā)動(dòng)。假如實(shí)在對(duì)時(shí)刻很靈敏,可能要考慮Rust等發(fā)動(dòng)速度更友好的語(yǔ)言。


            在發(fā)動(dòng)函數(shù)中初始化更多的共享資源:這個(gè)其實(shí)不能處理第一次冷發(fā)動(dòng)的時(shí)刻,可是能夠讓每次call的耗時(shí)更少。


            減縮包大?。簩?duì)于不必要的三方庫(kù)優(yōu)先移除,也能夠運(yùn)用更精簡(jiǎn)的版別進(jìn)行替換。


            定時(shí)激活:這個(gè)最早在AWS Lambda上廣泛運(yùn)用,其實(shí)本質(zhì)上是保存一個(gè)常駐實(shí)例,可是依靠的云廠商的機(jī)制。比如AWS Lambda大約30-40分鐘收回之前的活躍實(shí)例。這樣只需求一個(gè)定時(shí)觸發(fā)器就能夠進(jìn)行激活操作。這個(gè)辦法在一切Serverless渠道都能夠運(yùn)用。可是需求正確處理來(lái)自HTTP觸發(fā)器和Event觸發(fā)器的邏輯。