<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Serverless 工程實踐 | Serverless 應用開發(fā)觀念的轉變

          共 7467字,需瀏覽 15分鐘

           ·

          2021-09-18 00:30

          作者 | 劉宇(江昱)


          前言:在 Serverless 架構下,雖然更多精力是關注業(yè)務代碼,但是實際上對一些配置和成本也是需要關注的,并且必要的時候還需要根據(jù)配置與成本對 Serverless 應用進行配置和代碼優(yōu)化。



          Serverless 應用開發(fā)觀念的轉變



          Serverless 架構帶來的除了一種新的架構、一種新的編程范式,還包括思路上的轉變,尤其是開發(fā)過程中的一些思路轉變。有人說要把 Serverless 架構看成一種天然的分布式架構,需要用分布式架構的思路去開發(fā) Serverless 應用。誠然,這種說法是正確的。但是在一些情況下,Serverless 還有一些特性,所以要轉變開發(fā)觀念。

          1、文件上傳方法

          在傳統(tǒng) Web 框架中,上傳文件是非常簡單和便捷的,例如 Python 的 Flask 框架:

          f = request.files['file']f.save('my_file_path')

          但是在 Serverless 架構下,文件卻不能直接上傳,原因如下:


          • 一般情況下,一些云平臺的API網關觸發(fā)器會將二進制文件轉換成字符串,不便直接獲取和存儲;
          • 一般情況下,API 網關與 FaaS 平臺之間傳遞的數(shù)據(jù)包有大小限制,很多平臺限制數(shù)據(jù)包大小為 6MB 以內;
          • FaaS 平臺大多是無狀態(tài)的,即使存儲到當前實例中,也會隨著實例釋放而使文件丟失。

          所以,傳統(tǒng) Web 框架中常用的上傳文件方案不太適合在 Serverless 架構中直接使用。在 Serverless 架構中,上傳文件的方法通常有兩種:一種是轉換為 Base64 格式后上傳,將文件持久化到對象存儲或者 NAS 中,但 API 網關與 FaaS 平臺之間傳遞的數(shù)據(jù)包有大小限制,所以此方法通常適用于上傳頭像等小文件的業(yè)務場景。

          另一種上傳方法是通過對象存儲等平臺來上傳,因為客戶端直接通過密鑰等來將文件直傳到對象存儲是有一定風險的,所以通常是客戶端發(fā)起上傳請求,函數(shù)計算根據(jù)請求內容進行預簽名操作,并將預簽名地址返給客戶端,客戶端再使用指定的方法上傳,上傳完成之后,通過對象存儲觸發(fā)器等來對上傳結果進行更新等,如下圖所示。


          在 Serverless 架構下文件上傳文件示例


          以阿里云函數(shù)計算為例,針對上述兩種常見的上傳方法通過 Bottle 來實現(xiàn)。在函數(shù)計算中,先初始化對象存儲相關的對象等:

          AccessKey = {    "id": '',    "secret": ''}OSSConf = {    'endPoint': 'oss-cn-hangzhou.aliyuncs.com',    'bucketName': 'bucketName',    'objectSignUrlTimeOut': 60}#獲取/上傳文件到OSS的臨時地址auth = oss2.Auth(AccessKey['id'], AccessKey['secret'])bucket = oss2.Bucket(auth, OSSConf['endPoint'], OSSConf['bucketName'])#對象存儲操作getUrl = lambda object, method: bucket.sign_url(method, object, OSSConf['object    SignUrlTimeOut'])getSignUrl = lambda object: getUrl(object, "GET")putSignUrl = lambda object: getUrl(object, "PUT")
          #獲取隨機字符串randomStr = lambda len: "".join(random.sample('abcdefghijklqrstuvwxyz123456789 ABCDEFGZSA' * 100, len))

          第一種上傳方法,通過 Base64 上傳之后,將文件持久化到對象存儲:

          #文件上傳# URI: /file/upload# Method: POST@bottle.route('/file/upload', "POST")def postFileUpload():    try:        pictureBase64 = bottle.request.GET.get('picture', '').split("base64,")[1]        object = randomStr(100)        with open('/tmp/%s' % object, 'wb') as f:            f.write(base64.b64decode(pictureBase64))        bucket.put_object_from_file(object, '/tmp/%s' % object)        return response({            "status": 'ok',        })    except Exception as e:        print("Error: ", e)        return response(ERROR['SystemError'], 'SystemError')

          第二種上傳方法,獲取預簽名的對象存儲地址,再在客戶端發(fā)起上傳請求,直傳到對象存儲:

          #獲取文件上傳地址# URI: /file/upload/url# Method: GET@bottle.route('/file/upload/url', "GET")def getFileUploadUrl():    try:        object = randomStr(100)        return response({            "upload": putSignUrl(object),            "download": 'https://download.xshu.cn/%s' % (object)        })    except Exception as e:        print("Error: ", e)        return response(ERROR['SystemError'], 'SystemError')

          HTML 部分:

          <div style="width: 70%">    <div style="text-align: center">        <h3>Web端上傳文件</h3>    </div>    <hr>    <div>        <p>            方案1:上傳到函數(shù)計算進行處理再轉存到對象存儲,這種方法比較直觀,問題是 FaaS 平                   臺與 API 網關處有數(shù)據(jù)包大小上限,而且對二進制文件處理并不好。        </p>        <input type="file" name="file" id="fileFc"/>        <input type="button" onclick="UpladFileFC()" value="上傳"/>    </div>    <hr>    <div>        <p>            方案2:直接上傳到對象存儲。流程是先從函數(shù)計算獲得臨時地址并進行數(shù)據(jù)存儲(例如將                   文件信息存到 Redis 等),然后再從客戶端將文件上傳到對象存儲,之后通過對象                   存儲觸發(fā)器觸發(fā)函數(shù),從存儲系統(tǒng)(例如已經存儲到 Redis)讀取到信息,再對圖                   像進行處理。        </p>        <input type="file" name="file" id="fileOss"/>        <input type="button" onclick="UpladFileOSS()" value="上傳"/>    </div></div>

          通過 Base64 上傳的客戶端 JavaScript 實現(xiàn):

          function UpladFileFC() {    const oFReader = new FileReader();    oFReader.readAsDataURL(document.getElementById("fileFc").files[0]);    oFReader.onload = function (oFREvent) {        const xmlhttp = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new            ActiveXObject("Microsoft.XMLHTTP"))        xmlhttp.onreadystatechange = function () {            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {                alert(xmlhttp.responseText)            }        }        const url = "https://domain.com/file/upload"        xmlhttp.open("POST", url, true);        xmlhttp.setRequestHeader("Content-type", "application/json");        xmlhttp.send(JSON.stringify({            picture: oFREvent.target.result        }));    }}

          客戶端通過預簽名地址,直傳到對象存儲的客戶端 JavaScript 實現(xiàn):

          function doUpload(bodyUrl) {    const xmlhttp = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new Active        XObject("Microsoft.XMLHTTP"));    xmlhttp.open("PUT", bodyUrl, true);    xmlhttp.onload = function () {        alert(xmlhttp.responseText)    };    xmlhttp.send(document.getElementById("fileOss").files[0]);}

          function UpladFileOSS() { const xmlhttp = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new Active XObject("Microsoft.XMLHTTP")) xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { const body = JSON.parse(xmlhttp.responseText) if (body['url']) { doUpload(body['url']) } } } const getUploadUrl = 'https://domain.com/file/upload/url' xmlhttp.open("POST", getUploadUrl, true); xmlhttp.setRequestHeader("Content-type", "application/json"); xmlhttp.send();}

          整體效果如圖中所示。


          Serverless 構下文件上傳實驗 Web 端效果

          此時,我們可以在當前頁面進行不同類型的文件上傳方案實驗。

          2、文件讀寫與持久化方法

          應用在執(zhí)行過程中,可能會涉及文件的讀寫操作,或者是一些文件的持久化操作。在傳統(tǒng)的云主機模式下,可以直接讀寫文件,或者將文件在某個目錄下持久化,但是在 Serverless 架構下并不是這樣的。

          由于 FaaS 平臺是無狀態(tài)的,并且用過之后會被銷毀,因此文件并不能直接持久化在實例中,但可以持久化到其他的服務中,例如對象存儲、NAS 等。

          同時,在不配置NAS的情況下,F(xiàn)aaS 平臺通常情況下只具備 /tmp 目錄可寫權限,所以部分臨時文件可以緩存在 /tmp 文件夾下。

          3、慎用部分 Web 框架的特性

          (1) 異步

          函數(shù)計算是請求級別的隔離,所以可以認為這個請求結束了,實例就有可能進入一個靜默狀態(tài)。而在函數(shù)計算中,API 網關觸發(fā)器通常是同步調用(以阿里云函數(shù)計算為例,通常只在定時觸發(fā)器、OSS 事件觸發(fā)器、MNS 主題觸發(fā)器和 IoT 觸發(fā)器等幾種情況下是異步觸發(fā))。

          這就意味著當 API 網關將結果返給客戶端的時候,整個函數(shù)就會進入靜默狀態(tài),或者被銷毀,而不是繼續(xù)執(zhí)行完異步方法。所以通常情況下像 Tornado 等框架就很難在 Serverless 架構下發(fā)揮其異步的作用。當然,如果使用者需要異步能力,可以參考云廠商所提供的異步方法。

          以阿里云函數(shù)計算為例,阿里云函數(shù)計算為用戶提供了一種異步調用能力。當函數(shù)的異步調用被觸發(fā)后,函數(shù)計算會將觸發(fā)事件放入內部隊列,并返回請求 ID,而不會返回具體的調用情況及函數(shù)執(zhí)行狀態(tài)。如果用戶希望獲得異步調用的結果,可以通過配置異步調用目標來實現(xiàn),如圖所示。


          函數(shù)異步功能原理簡圖

          (2) 定時任務

          在 Serverless 架構下,應用一旦完成當前請求,就會進入靜默狀態(tài),甚至實例會被銷毀,這就導致一些自帶定時任務的框架沒有辦法正常執(zhí)行定時任務。函數(shù)計算通常是由事件觸發(fā),不會自主定時啟動。例如 Egg 項目中設定了一個定時任務,但是在實際的函數(shù)計算中如果沒有通過觸發(fā)器觸發(fā)該函數(shù),該函數(shù)不會被觸發(fā),也不會從內部自動啟動來執(zhí)行定時任務,此時可以使用定時觸發(fā)器,通過定時觸發(fā)器觸發(fā)指定方法來替代定時任務。

          4、要注意應用組成結構

          (1) 靜態(tài)資源與業(yè)務邏輯

          在 Serverless 架構下,靜態(tài)資源更應該在對象存儲與 CDN 的加持下對外提供服務,否則所有的資源都在函數(shù)中。通過函數(shù)計算對外暴露,不僅會讓函數(shù)的業(yè)務邏輯并發(fā)度降低,也會造成更多的成本。尤其是將一些已有的程序遷移到 Serverless 架構上,例如 Wordpress 等,更要注意將靜態(tài)資源與業(yè)務邏輯進行拆分,否則在高并發(fā)情況下,性能與成本都將會受到比較嚴峻的考驗。

          (2) 業(yè)務邏輯的拆分

          在眾多云廠商中,函數(shù)的收費標準都是依靠運行時間、配置的內存以及產生的流量收費的。如果一個函數(shù)的內存設置不合理,會導致成本成倍增加。想要保證內存設置合理,更要保證業(yè)務邏輯結構的可靠性。

          以阿里云函數(shù)計算為例,一個應用有兩個對外接口,其中有一個接口的內存消耗在 128MB 以下,另一個接口的內存消耗穩(wěn)定在 3000MB 左右。這兩個接口平均每天會被觸發(fā) 10000 次,并且時間消耗均在 100 毫秒。如果兩個接口寫到一個函數(shù)中,那么這個函數(shù)可能需要將內存設置在 3072MB,同時用戶請求內存消耗較少的接口在冷啟動情況下難以得到較好的性能;如果兩個接口分別寫到函數(shù)中,則兩個函數(shù)內存分別設置成 128MB 以及 3072MB 即可,如表所示。


          通過上表可以明確看出合理、適當?shù)夭鸱謽I(yè)務會在一定程度上節(jié)約成本。上面例子的成本節(jié)約近 50%。


          關于作者:
          劉宇(江昱)國防科技大學電子信息專業(yè)在讀博士,阿里云 Serverless 產品經理,阿里云 Serverless 云布道師,CIO 學院特聘講師。


          新書推薦





          本書會通過多個開源項目、多個云廠商的多款云產品,以及多種途徑向讀者介紹什么是 Serverless 架構、如何上手 Serverless 架構、不同領域中 Serverless 架構的應用以及如何從零開發(fā)一個 Serverless 應用等。本書可以幫助讀者將 Serverless 架構融入到自己所在的領域,把 Serverless 項目真實落地,獲得 Serverless 架構帶來的技術紅利。

          Serverless 工程實踐系列



          Serverless 工程實踐 | 從云計算到 Serverless

          Serverless 工程實踐 | 細數(shù) Serverless 的配套服務

          Serverless 工程實踐 | 傳統(tǒng) Web 框架遷移                 


          ??戳閱讀原文,立即購買!
          瀏覽 33
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲无码77777 | 91精品综合久久久久久五月丁香 | 91人妻人人澡人人爽精品 | 美女逼网站 | 人人撸人人爱 |