對Serverless架構的一點體驗和思考

阿呆少爺發表於2017-08-07

發端

雲端計算機經過這麼多年的發展,逐漸進化到使用者僅需關注業務和所需的資源。通過Swarm、K8S這些編排工具,容器服務讓開發者的體驗達到很完美的境界。我曾經覺得Docker可以替代虛機,使用者只要關注自己的計算和需要的資源就行,不需要操心到機器這一層。但是因為Docker對資源的隔離不夠好,各大雲廠商的做法還是一個Docker對應一臺虛機,不僅成本高,給使用者暴露虛機也多餘了。

使用者為什麼需要關注業務執行所需要的CPU、記憶體、網路情況?還有沒有更好的解決方案?Serverless架構應運而生,讓人們不再操心執行所需的資源,只需關注自己的業務邏輯,並且為實際消耗的資源付費。可以說,隨著Serverless架構的興起,真正的雲端計算時代才算到來了。

容器在開發模式方面並沒有提出新的想法,大家還是在用傳統的那一套開發模式,需要寫一個大而全的後端服務。與之對比,Serverless架構是事件驅動的,這樣讓後端的開發體驗變得跟前端和移動端很類似了。針對不同客戶的需求,先讓其購買好相關的資源,然後一個個填坑,給不同的產品新增各種事件處理邏輯就行。這就跟iOS開發一樣,介面寫出來,然後處理一個個事件就好了,大家都很容易理解這種開發模式。

image.png

AWS Lambda體驗

AWS在2014年11月的re:Invent大會上推出Lambda,經過將近三年的發展,已經達到了非常完善的程度。Lambda主要有三個作用。

  1. 跟API Gateway結合起來,方便快捷地提供API服務。
  2. 串聯關鍵產品,比如在DDB插入一條新資料之後,觸發Lambda執行,讀取新記錄送給搜尋引擎建索引。
  3. 擴充套件功能,比如Cognito User Pool提供非常多的點,方便使用者在登入的時候增加自己的處理邏輯。
    image.png

AWS Lambda支援多種語言開發,比如C#、Java、Node.js和Python,擁有廣泛的群眾基礎。

AWS Lambda在除北京之外的所有region均可用。AWS中國支援的產品可以參考:地區表

image.png

Serverless Reference Architecture: Mobile Backend是一個非常好的例項,講述瞭如果通過Serverless架構實現一個App。

這個App的主要功能類似Evernote,支援上傳圖片,編寫和上傳文章。功能非常簡單,但是涉及到的產品非常多,玩法也非常老練。

1 2 3
image.png image.png image.png

整個demo用到的雲產品和它們相互之間的關係如下圖所示。除了Lambda本身,IAM、API Gateway等產品也發揮了巨大的作用。

$ tree cloudformation lambda-functions 
cloudformation
├── config-helper.template
├── mobile-backend-no-cloudfront.template //去除CloudFront相關配置的template檔案。在CloudFormation控制檯上傳該檔案。
└── mobile-backend.template //如果CloudFront可用的話,上傳這個template檔案也OK。
lambda-functions //Lambda程式碼已經壓縮好並放到一個公共的S3 bucket裡面,所以不用管這些程式碼。
├── search
│   └── index.js //CloudSearch搜尋介面的程式碼
├── stream-handler
│   └── index.js //DDB觸發建索引的程式碼
└── upload-note
    └── index.js //新增文章介面的程式碼,主要是寫DDB。

image.png

配置

CloudFormation真的很方便,template上傳之後,相關的資源就建立和設定好了。cloudformation目錄下有兩個template檔案,只需上傳mobile-backend.template,它會把config-helper.template載入好。阿里雲對應的產品是:資源編排ROS

image.png

看起來API Gateway、Cognito、CloudSearch這幾款個產品對CloudFormation支援的並不好,所以還需要通過文章中那麼多命令列和Web控制檯上的設定。

為了能執行這些命令,要把AWS CLI配置好,region設定為us-east-1(弗吉尼亞北部),因為文章中存放Lambda程式碼壓縮包的S3也是在us-east-1區域的。

$ aws configure              
AWS Access Key ID [****************X3CA]: 
AWS Secret Access Key [****************Qo3J]: 
Default region name [us-east-1]:

$ cat ~/.aws/config 
[default]
region = us-east-1
配置裡面的一些坑

一個坑是CloudFront可能沒有初始化好,導致CloudFormation建立失敗。懶得去配置了,所以我乾脆刪除了CloudFormation裡面CloudFront相關的配置。這樣並不會影響體驗。

image.png

image.png

CloudFormation有一個資源建立失敗後,會rollback。它把資源的建立當做一個事務來處理,全部成功才行。

image.png

客戶端使用Swift 2.3寫的。因為程式碼也比較簡單,所以Convert到3.0就行。後面接著會報Ambiguous use of `continue`錯誤,類似下面這樣的程式碼使用一對小括號括住block就行。

let noteApiClient = APINotesApiClient(forKey: "USEast1NoteAPIManagerClient")
noteApiClient?.notesPost(noteRequest).continue ({ (task) -> AnyObject! in
    
    if let error = task?.error {
        print("Failed creating note: [(error)]")
    }
    if let exception = task?.exception {
        print("Failed creating note: [(exception)]")
    }
    if let noteResponse = task?.result as? APICreateNoteResponse {
        if((noteResponse.success) != nil) {
            print("Saved note successfully")
        }else {
            print("Unable to save note due to unknown error")
        }
    }
    return task
})

程式執行起來之後,Upload Image到S3沒有問題。但是上傳文章的時候會報forbidden的錯誤。Xcode裡面會列印下面這個錯誤。通過Charles抓包,發現伺服器端給了錯誤提示。

image.png

需要在Usage Plans裡面Add API Stage裡面操作一下,API和Stage對上就好了。文章中沒有提到這個配置。

image.png

一些技術細節

App直接面對API Gateway和S3,要先從Cognito Identity Pool獲取到一個id(Unauthenticated),這個Pool對應MobileClientRole角色,可以看一下這個角色的具體配置,主要是針對S3和API Gateway相關action的allow 。這裡直接使用了API Gateway生成的SDK,結合Cognito Identity Pool用著也挺方便。API Gateway也支援使用Cognito UserPool做驗證器,不需要SDK,用起來更加方便一些,詳細資訊可以參看:[對AWS Cognito的一些理解
](http://www.jianshu.com/p/112438fb86aa)

image.png

image.png

/notes的post介面交給NotesApiFunction Lambda來處理,在控制檯可以看得很清楚。

image.png

DDB變動會觸發執行DynamoStreamHandlerFunction這個Lambda,從配置裡面也可以很清楚看到這個trigger。

image.png

效果

S3裡面可以看到圖片。

image.png

Dynamo DB裡面可以看到Post資料。

image.png

但是CloudSearch裡面Searchable Documents卻一直都是0。

image.png

可以看看DynamoStreamHandlerFunction這個Lambda的資料,發現呼叫都失敗了。

image.png

去CloudWatch裡面看看。提示TypeError: Cannot read property `S` of undefined

image.png

對著stream-handler/index.js看了一下,發現拿到Dynamo DB的資料之後,要通過.S將其轉型為字串型別。再對著文件看看,其實是沒有毛病的,所以這個問題還不知道怎麼解決。

function createSearchDocuments(records) {
    var searchDocuments = [];

    for(var i = 0; i<records.length; i++) {
        var record = records[i];

        if (record.eventName === "INSERT") {
            var searchDocument = {
                type : `add`,
                id : record.dynamodb.Keys.noteId.S,
                fields : {
                    headline : record.dynamodb.NewImage.headline.S,
                    note_text : record.dynamodb.NewImage.text.S
                }
            };
            searchDocuments.push(searchDocument);
        }
    }
    return searchDocuments;
}

這個問題突然就消失了,建索引和檢索功能都正常了,amazing~

image.png

image.png

費用

Lambda根據使用記憶體和呼叫次數收費。記憶體最低是128MB。具體資訊請參看:Lambda 定價詳情

image.png

image.png

這個App使勁玩,花不了幾塊錢的。Lambda累計執行了240秒,沒有花錢,主要是S3和資料傳輸花了點錢。

image.png

image.png

Serverless成功的關鍵

擁有豐富的產品,並且打通所有的雲產品,是Serverless成功的前提條件。Lambda不適合處理複雜的業務邏輯,比較適合作為膠水程式碼,粘合關鍵的產品。另外就是Lambda不管怎麼完善,可能只能解決80%的問題,剩下20%的邏輯需要使用者自己寫服務,通過docker釋出,然後給Lambda或者使用者使用。這種混合的編碼方式可能是未來的主流開發模式。

image.png

Serverless的主要優點

  1. 開發者更加專注於業務邏輯,開發效率更高。開發一個典型的伺服器端專案,需要花很多時間處理依賴、執行緒、日誌、釋出和使用服務、部署及維護等相關的工作,基於Serverless架構則不需要操心這些工作。
  2. 使用者為實際使用的資源付費。使用者購買的ECS使用時間一般不到5成,但是為另外5成閒置時間付費了。Lambda按照執行的時間收費,成本會低很多。
  3. NO Architecture,NO Ops。架構師的責任是設計一個高可用、高擴充套件的架構。運維負責整個系統穩定可靠地執行,適當縮減和增加資源。大型雲廠商能保證產品的高可用,Serverless架構本身就是高擴充套件的。Serverless不再需要伺服器端的工作人員,給客戶節省了大量的資源。架構師和運維的同學應該好好思考一下未來的出路了。架構師可以轉型去做銷售,整理使用者的需求,然後寫寫CloudFormation的template就好了。
  4. 還是成本。IT行業一些領先的公司基礎設施非常完善,開發工程師寫好程式碼,然後通過釋出平臺釋出,感覺也是挺方便的。比起Serverless的架構,成本還是要高不少。

    1. 機器成本。日常、預發、線上,1+1+2=4臺伺服器少不了。
    2. 時刻要關注業務資料,盤點資源,看看是否需要擴容和縮減資源。擴容容易,縮減難,造成大量資源閒置。
    3. 全鏈路壓測是不是很煩?

Serverless的主要缺點

  1. 排查問題困難,因為邏輯散落在各處,一個操作可能觸發成百上千個Lambda執行。AWS的X-Ray和CloudWatch等產品可以幫助使用者排查問題。
    image.png
  2. 準備runtime需要時間,流量瞬間爆發容易導致超時。
  3. 帶狀態的Lambda寫起來很困難。
  4. Lambda執行有諸多資源限制,比如執行時長、記憶體、磁碟、開啟的檔案數量等。
    image.png
  5. 廠商鎖定。雲端計算是贏者通吃的行業,大而全的雲廠商優勢巨大,Serverless加劇了這種趨勢。以前使用者還需要自己寫很多伺服器端的邏輯,遷移的時候,把伺服器端程式碼重新部署一下。採用Serverless架構之後,程式碼都是各個平臺的Lambda程式碼片段,沒法遷移。從客戶的角度來看,是不希望自己被某家雲廠商所綁架的。所以雲端計算需要有一個標準,產品需要標準化,方便使用者無縫在各種雲之間遷移。

阿里雲對Serverless的支援情況

阿里雲在今年四月份南京雲棲大會上推出了自己的Serverless產品:函式計算,目前只支援API Gateway和OSS,並且只能在華東2區域使用。還沒有形成體系,很難滿足使用者多樣的需求。

推廣Serverless不是一件容易的事情,一是現有產品上雲要接入的東西有點多,比如售賣、許可權、風控、服務等級等,未來還需要接入Serverless。開發團隊很累。第二個是,現有大量的產品要一個個去推動做改造,不是一件容易的事情。

不過阿里雲也在很努力完善對Serverless的支援,未來可期。函式計算攜手API閘道器輕鬆實踐Serverless架構

image.png

雲棲社群有一些相關的文章:阿里雲 Serverless Computing,講得非常好,可以瞭解一下。

MBaaS/MPaaS為什麼不賺錢?

移動開發領域最早有一些廠商提供移動推送、Crash收集分析、移動資料分析等基礎服務,也就是MPaaS。然後逐漸有一些廠商開始提供資料庫、儲存、配置等相關的服務,在Web控制檯上操作,移動端直接使用這些服務,不需要經過伺服器端中轉,這就是MBaaS。

目前移動開發領域的服務提供商,比如Facebook的Parse(已關閉)、Firebase(已被Google收購,現在很強大)、國內的LeanCloud都發展得不好。我覺得主要還是因為產品線不夠豐富,只能滿足一些小App或者App發展初期的需要。MBaaS/MPaaS依託主流雲廠商豐富的產品線,通過類似Lambda機制將這些產品串聯起來,應該會有不錯的發展。

參考資料

  1. 十年生聚,十年教訓——我眼中的雲端計算
  2. Liming的動態
  3. 夏日清風 – 基於Docker Swarm的極簡Serverless實踐
  4. InfoQ虛擬研討會:無伺服器計算的實踐方法
  5. 誘人卻非萬能,理性看待Serverless的落地
  6. 對AWS Cognito的一些理解


相關文章