Serverless 實戰:通過 Component 實現多地域部署容災

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

單點故障是實際生產中無法避免的,單副本的存儲方案也早已無法滿足業務的可靠性要求。現在,我們通常都會做雙機存儲架構,會涉及到主備、主從、主主模式。

image

在 Serverless 架構下,高可用方案或者容災方案是否還需要主備、主從以及主主等模式?如果還需要,那麼又是什麼樣子?

Serverless 與多地域部署

針對服務可用性,幾乎每個雲廠商都會有非常高的承諾,但是我們也不能掉以輕心,認爲不會出現故障導致不可用,容災方案是必須要有的。

在傳統主機時代有主備、主從以及主主模式,這個模式更多針對的是單臺機器或者某個集羣。但是在 Serverless 架構下,沒有機器和集羣的概念(至少在用戶層面沒有),是不是就表示在 Serverless 架構下無法做容災?

理論上,雲廠商會保證整個服務的可用性,如果雲廠商管理的某個機器出現故障,機器會被及時剔除,確保新的函數在安全、穩定、健康的環境下啓動,正常提供服務。但在實際情況中,由於某些原因,雲廠商也可能會在某個地域出現大規模故障,這時如何確保服務依舊可用,而不是苦苦等待雲廠商的恢復?

針對單地域解析的網站,我們可以實現多地域的主備方案。在雲函數中,多地域的主備方案更加經濟實惠,因爲函數是按量付費的,完全可以將函數複製到其他的地域,只要不進行觸發,就不會產生額外的費用。相對於傳統主機時代的主備模式,這種主備方案顯得更加人性化。

image

一般情況下,單地域部署的服務中比較容易出問題的是 API 網關服務、雲函數服務、數據庫服務。其中,數據庫服務可以考慮跨地域主從、跨區域同步,一旦出現問題,就在函數中做一個負載,確保整體數據不會出現問題,在騰訊雲的雲數據庫描述下可以看到:

本地 IDC 機房 MySQL 數據庫與雲數據庫 MySQL 之間可以通過數據遷移服務實時同步數據,本地 IDC 機房如遇到斷電、網絡故障等引起數據庫服務中斷,可迅速切換數據庫服務至作爲災難備份的雲數據庫 MySQL 實例,實現數據庫容災;同時,雲數據庫 MySQL 可支持同城多可用區災備 / 跨城災備,保障高可用。

所以說,數據庫相關服務的容災可以通過備用數據庫來提高可用性。

那麼雲函數和 API 網關怎麼解決?

以多地域部署容災爲例,我們可以考慮這樣的架構:

image

同樣是作爲單地域解析服務,相對來說,多地域部署更加安全穩定,一旦某個地域的服務出現問題(例如 API 網關,雲函數),都可以通過監控程序及時發現,並且迅速切換解析到其它地域。多地域部署的監控函數與時間觸發器進行結合,定期進行網站可用性的排查,一旦出現問題,就可以在雲解析層面進行解析切換,實現單地域服務的多地域部署容災方案:

image

這個方案的邏輯是先請求服務是否可用,如果不可用,則獲取容災列表,剔除不可用的服務,並通過雲解析進行可用區的解析。在實際生產中,一旦確定某個服務不可用,還要進行精確告警,在獲得到不可用解析記錄對應的服務之後,通過郵件或者企業微信、短信等方法進行告警。

至此,一個簡單版的“高可用”服務就算做好了,有的讀者可能有所疑問:

  • 切換解析不需要時間嗎?怎麼確保 TTL 按時生效?
  • 對服務進行修復,是否比切換解析更加靠譜呢?

針對問題 1,其實切換解析是需要時間的,雖然一小部分的機房可能不會按照設定的 TTL 進行生效,但是大部分的機房都是可以按照設定及時生效,所以需要注意的是,在添加解析的時候要儘可能地確保 TTL 時間短一些,目前騰訊雲的雲解析付費版最低 TTL 可以設置爲 1s,免費版是 600s。

針對問題 2,在雲函數上運行服務很少會因爲流量太高導致服務不可用,或者服務中存在 bug 導致整個項目不可用,因爲雲廠商會解決很大一部分的可用性,例如流量併發問題等。另外,就算是程序中存在 bug,在 Serverless 架構下,函數的前一次後一次運行實際上關聯性不大,所以完全可以通過告警來確定,人爲排查消滅隱患。事實上,在 Serverless 架構下出現大規模服務性災難,多數情況都是雲廠商的問題(此處已經排除掉用戶代碼層面的 bug),而這種問題一旦出現,就不是我們能夠掌控的了,是否可以修復、什麼時候修復。

image

如果是 API 網關層面出現問題,可以通過上一層來解決,例如雲解析的切換;如果是函數層面出現問題,可以考慮切換到 API 網關到同區域的備用函數;如果是函數服務的整個區域性故障(概率非常低),可以考慮切換解析到備用區。

如果不是單地域提供服務,那麼就需要考慮多地域部署、多地域就近接入以及多地域容災方案。

image

從上圖可以看到,我們將一個域名,劃分地域進行解析,例如華北、華東兩個地區,就可分別解析到北京 1 區、北京 2 區兩個不同的機房中兩臺不同的服務器上。當其中一個服務不可用時,其他區域不受影響,可以使用雲函數對解析進行修改,將其解析到每個地區的備用服務上。

image

整體結構圖:

image

傳統的服務需要每個地區部署多套服務,無疑大大增加了成本,但是在 Serverless 架構下,即使部署了多套雲函數還是按量付費,大大節約了成本。

若採用 Serverless 架構作爲後端服務,以華北地區爲例,華北地區用戶在訪問後端服務的時候,通過 DNS 重定向到北京區的 API 網關,然後再由 API 網關觸發北京區雲函數,此時我們需要兩個雲函數對服務進行監控,一個函數對雲函數進行監控,當雲函數服務失效之後,可以將 API 網關綁定到備用的函數上,另一個監控是對 API 網關進行監控,當某個地域的 API 網關失效之後,可以對解析進行修改,重定向到備用地域的 API 網關上,儘可能快速的保證服務的可用性。

如果想要讓服務更穩定,可以增加數據庫 / 對象存儲的主備與監控,以及數據庫 / 對象存儲封裝函數的主備與監控,這樣就可以在四個層次做監控告警以及服務保障:在我們的服務中,通常數據庫或者存儲模塊不會同時在多個區域部署,也可能只有一套主備服務,此時,可以通過對數據庫和對象存儲做一層封裝,即在外層增加一個對應的函數,通過內網對數據庫以及對象存儲進行數據轉發等,通過外部雲函數調用 invoke(專線調用)大幅度降低由於網絡原因造成的延時,當雲數據庫 / 對象存儲出現問題,在接入層(數據庫 / 對象存儲封裝函數)一側,進行切換,將雲數據庫 / 對象存儲切換到備用服務上,並進行告警;當接入層發生故障,無法繼續服務時,在邏輯函數初(北京區 / 上海區 / 廣州區),切換封裝函數,即通過內部專線(函數間調用)調用備用接入層函數;同理,當邏輯函數 / 業務函數出現故障,監控腳本對 API 網關側的後端服務進行切換,切換到備用邏輯函數 / 業務函數上;如果當 API 網關出現故障,無法繼續提供服務,則只能在解析層面做切換。在整個這樣的一個流程中,每一階段或者說每一層面都有自身的負載機制,主備策略,可以根據不同組件出現故障的實際情況,進行多層級的自動切換,進而保證業務可用時長的一個最大化。

此處,有讀者可能有疑問:爲什麼某個函數會無法提供服務?底層服務的容災機制,不是雲廠商要提供的麼?理論上,這個容災機制是雲廠商提供的,並且函數是無狀態的,只要確保業務邏輯無問題,是不需要進行某些層級的主備容災等。但是實際上,各個雲廠商均沒有辦法保證某個服務 100% 可用。例如 2019 年 6 月 2 日凌晨 2 點,亞馬遜雲 AWS 突發受大規模故障,直到當天下午 1 點 48 分故障解除,故障時間將近 12 小時。所以,雖然雲廠商會提供相對安全與可靠的容災機制和服務,但還是很有必要在自身層面額外處理一下,儘可能保證服務安全與穩定。

通過 Serverless Framework 進行多地域部署與解析

函數的多地域部署

以騰訊云爲例,基礎的 Component 跨地域部署不是很容易實現。雖然修改區域將函數部署到多個地域是可以實現的,但實際部署時每個區域的函數還會有一些額外的配置,所以這個時候可以藉助多地域部署的組件來實現:tencent-scf-multi-region

相對於傳統的tencent-scf組件而言,這個組件的 yaml 將region字段變成了兼容list形式,同時增加了子地域的額外配置,例如 yaml:

hello_world:
  component: '@serverless/tencent-scf-multi-region'
  inputs:
    codeUri: ./
    description: This is a template function
    region: 
      -ap-guangzhou
      - ap-shanghai
    environment:
      variables:
        ENV_FIRST: env1
        ENV_SECOND: env2
    handler: index.main_handler
    memorySize: 128
    name: hello_world
    runtime: Python3.6
    timeout: 3
    events:
      - apigw:
          name: serverless_test
          parameters:
            protocols:
              - http
            description: the serverless service
            environment: release
            endpoints:
              - path: /users
                method: POST
              - path: /usersss
                method: POST
    ap-guangzhou:
      environment:
        variables:
          ENV_FIRST: env2
    ap-shanghai:
      events:
        - apigw:
            name: serverless_test
            parameters:
              protocols:
                - http
              description: the serverless service
              environment: release
              endpoints:
                - path: /usersd
                  method: POST

測試部署效果:

$ sls --debug
  
    DEBUG ─ Resolving the template's static variables.
    DEBUG ─ Collecting components from the template.
    DEBUG ─ Downloading any NPM components found in the template.
    DEBUG ─ Analyzing the template's components dependencies.
    DEBUG ─ Creating the template's components graph.
    DEBUG ─ Syncing template state.
    DEBUG ─ Executing the template's components graph.
    DEBUG ─ Compressing function hello_world file to /Users/dfounderliu/Desktop/ServerlessComponents/test/scf_test/.serverless/hello_world.zip.
    DEBUG ─ Compressed function hello_world file successful
    DEBUG ─ Uploading service package to cos[sls-cloudfunction-ap-guangzhou-code]. sls-cloudfunction-default-hello_world-1583816589.zip
    DEBUG ─ Uploaded package successful /Users/dfounderliu/Desktop/ServerlessComponents/test/scf_test/.serverless/hello_world.zip
    DEBUG ─ Creating function hello_world
    DEBUG ─ Updating code... 
    DEBUG ─ Updating configure... 
    DEBUG ─ Created function hello_world successful
    DEBUG ─ Setting tags for function hello_world
    DEBUG ─ Creating trigger for function hello_world
    DEBUG ─ Starting API-Gateway deployment with name hello_world.ap-guangzhou-hello_world.serverless_test in the ap-guangzhou region
    DEBUG ─ Service with ID service-p14470dc created.
    DEBUG ─ API with id api-pg3ihnoi created.
    DEBUG ─ Deploying service with id service-p14470dc.
    DEBUG ─ Deployment successful for the api named hello_world.ap-guangzhou-hello_world.serverless_test in the ap-guangzhou region.
    DEBUG ─ API with id api-op4jqvba created.
    DEBUG ─ Deploying service with id service-p14470dc.
    DEBUG ─ Deployment successful for the api named hello_world.ap-guangzhou-hello_world.serverless_test in the ap-guangzhou region.
    DEBUG ─ Deployed function hello_world successful
    DEBUG ─ Compressing function hello_world file to /Users/dfounderliu/Desktop/ServerlessComponents/test/scf_test/.serverless/hello_world.zip.
    DEBUG ─ Compressed function hello_world file successful
    DEBUG ─ Uploaded package successful /Users/dfounderliu/Desktop/ServerlessComponents/test/scf_test/.serverless/hello_world.zip
    DEBUG ─ Creating function hello_world
    DEBUG ─ Updating code... 
    DEBUG ─ Updating configure... 
    DEBUG ─ Created function hello_world successful
    DEBUG ─ Setting tags for function hello_world
    DEBUG ─ Creating trigger for function hello_world
    DEBUG ─ Starting API-Gateway deployment with name hello_world.ap-shanghai-hello_world.serverless_test in the ap-shanghai region
    DEBUG ─ Service with ID service-7daktopz created.
    DEBUG ─ API with id api-4v40ce4u created.
    DEBUG ─ Deploying service with id service-7daktopz.
    DEBUG ─ Deployment successful for the api named hello_world.ap-shanghai-hello_world.serverless_test in the ap-shanghai region.
    DEBUG ─ API with id api-emkl7ov4 created.
    DEBUG ─ Deploying service with id service-7daktopz.
    DEBUG ─ Deployment successful for the api named hello_world.ap-shanghai-hello_world.serverless_test in the ap-shanghai region.
    DEBUG ─ Starting API-Gateway deployment with name hello_world.ap-shanghai-hello_world.serverless_test in the ap-shanghai region
    DEBUG ─ Using last time deploy service id service-7daktopz
    DEBUG ─ Updating service with serviceId service-7daktopz.
    DEBUG ─ API with id api-2zag45hq created.
    DEBUG ─ Deploying service with id service-7daktopz.
    DEBUG ─ Deployment successful for the api named hello_world.ap-shanghai-hello_world.serverless_test in the ap-shanghai region.
    DEBUG ─ Deployed function hello_world successful
  
    hello_world: 
      ap-guangzhou: 
        Name:        hello_world
        Runtime:     Python3.6
        Handler:     index.main_handler
        MemorySize:  128
        Timeout:     3
        Region:      ap-guangzhou
        Namespace:   default
        Description: This is a template function
        APIGateway: 
          - serverless_test - POST - http://service-p14470dc-1256773370.gz.apigw.tencentcs.com/release/users
          - serverless_test - POST - http://service-p14470dc-1256773370.gz.apigw.tencentcs.com/release/usersss
      ap-shanghai: 
        Name:        hello_world
        Runtime:     Python3.6
        Handler:     index.main_handler
        MemorySize:  128
        Timeout:     3
        Region:      ap-shanghai
        Namespace:   default
        Description: This is a template function
        APIGateway: 
          - serverless_test - POST - http://service-7daktopz-1256773370.sh.apigw.tencentcs.com/release/users
          - serverless_test - POST - http://service-7daktopz-1256773370.sh.apigw.tencentcs.com/release/usersss
          - serverless_test - POST - http://service-7daktopz-1256773370.sh.apigw.tencentcs.com/release/usersd
  
    35s › hello_world › done

通過以上部署,就可以成功將函數部署到不同的地域,並且針對不同地域進行額外的配置。

上層服務的多地域部署與解析

就目前來看,tencent-scf更多是一個基礎組件,更多人則是在使用 Koa、Express 等組件,那麼對於這種相對高階的組件,是否可以多地域部署呢?從目前文檔的描述來看是可以進行多地域部署,且可以進行自動解析,以tencent-tornado爲例:

TornadoTest:
  component: '@serverless/tencent-tornado'
  inputs:
    region:
      - ap-guangzhou
      - ap-shanghai
    functionName: tornadoFunctionTest
    tornadoProjectName: app
    code: ./
    functionConf:
      timeout: 10
      memorySize: 256
      environment:
        variables:
          TEST: vale
      vpcConfig:
        subnetId: ''
        vpcId: ''
    apigatewayConf:
      protocols:
        - http
      environment: release
      customDomain:
        - domain: anycodestest1.com
          isDefaultMapping: 'FALSE'
          pathMappingSet:
            - path: /
              environment: release
          protocols:
            - http
        - domain: anycodestest2.com
          isDefaultMapping: 'FALSE'
          pathMappingSet:
            - path: /
              environment: release
          protocols:
            - http
    cloudDNSConf:
      ttl: 603
      status: enable
    ap-guangzhou:
      functionConf:
        timeout: 20
      apigatewayConf:
        protocols:
          - https
      cloudDNSConf:
        recordLine:
          - 電信
          - 聯通

部署結果:

  TornadoTest: 
    functionName: tornadoFunctionTest
    ap-shanghai: 
      apiGatewayServiceId: service-mdnjhsp3
      url:                 http://service-mdnjhsp3-1256773370.sh.apigw.tencentcs.com/release/
    ap-guangzhou: 
      apiGatewayServiceId: service-nh6xgutk
      url:                 https://service-nh6xgutk-1256773370.gz.apigw.tencentcs.com/release/
    DNS:          Please set your domain DNS: f1g1ns1.dnspod.net | f1g1ns1.dnspod.net

通過這樣一個組件,就可以完成框架的跨地域部署與解析。

總結

至此,我們基本完成了一個基於 Serverless 的高可用框架的案例探討,從對單解析的分析,到對多解析的策略制定,再到最後基於 Serverless 架構的高可用模型,雖然文中案例僅僅可以作爲學習參考使用,在實際生產中會面臨很多難題,有些地方還需要針對實際項目做一些特殊的修改和修正,但是這樣一個簡單的基於 Serverless 架構的高可用模型,基本上可以發揮出 Serverless 架構的特點,包括 Serverless 架構的按量付費功能,在不使用的時候則不需要收費,在部署多套雲函數的時候不會因爲部署量增加而產生額外的費用;在這個項目中,包括 API 網關等觸發器對函數進行觸發,也會包括函數間的編排和調用,更有 FaaS 與 BaaS 緊密結合,通過專線跨地域 Invoke,在外層還會增加多套監控告警函數以及 DNS 切換函數、雲函數切換函數等儘可能保證服務的穩定與可用性;爲了更加簡單的進行多地域部署,還通過了 Serverless Framework 實現了多地域部署方案。

在實際生產生活中,無論是單地域服務還是多地域就近接入服務,多地域部署容災都是很重要的,尤其在 Serverless 架構下,按量付費讓主備模式成本驟降,100% 可用性幾乎是一個不可能事件,但我們可以共同探討相對優秀的高可用方案。

【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-07-30
本文作者:劉宇
本文來自:“infoq”,瞭解相關信息可以關注“infoq

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章