ABT 鏈網是怎樣建成的?

題記

昨天,也就是 3 月 29 日,ABT Network(ABT 鏈網) 正式發佈。ABT Network 以徹底去中心化方式鏈接編織多條區塊鏈造成的網絡,以雲節點和織鏈爲網的方式從新定義了新一代區塊鏈基礎架構。本文談談 ABT Network 誕生前發生的有趣經歷。node

爲方便閱讀,先簡單介紹一下本文談到的一些概念:git

  • ABT Network:多條使用 ArcBlock 技術打造的區塊鏈造成的網路。數據庫

  • ABT Chain Node:ArcBlock 使用 Forge Framework 打造的區塊鏈節點軟件。瀏覽器

  • Forge Framework:ArcBlock 爲區塊鏈開發打造的框架,能夠看作區塊鏈世界裏的 Ruby on Rails。安全

打造人人均可部署的節點

在開發 Forge Framework 和 ABT Chain Node 時,咱們有一個深深的信念:運行在 Forge 之上的區塊鏈項目能夠是陽春白雪,也能夠是下里巴人;能夠是每日千百萬級 transaction 的大型應用,也能夠是獨立開發者及其小圈子的自娛自樂。於是,一個節點只要有過得去的算力,就能夠運行 Forge,這樣,只要願意,人人均可以部署本身可負擔的節點。網絡

那什麼算是「過得去的算力」呢?考慮到 App 開發者的開發期的經濟能力,咱們將其定位在單節點月支出在 $15 之內,在 Digital Ocean 上,這對應:架構

也就是 1GB / 1CPU / 25GB disk 一路到 2GB / 2CPU / 60GB disk 的乞丐版雲主機。併發

在今年一二月份的大部分開發時間裏,咱們都在使用 $5 的至尊乞丐版主機 —— 並且,咱們一口氣在美西 (SF),美東 (NY),西歐 (London) 和東南亞 (Singapore) 部署了四個節點,組成一個 P2P 網絡,來開發 Forge。咱們相信,極端惡劣的環境,能打造儘量健壯的軟件,讓各類問題都提早暴露出來。app

有了環境,咱們須要有足夠模擬真實應用場景的流量。爲此咱們開發了一個 simulator(模擬器),而且作了一個簡單的描述語言來描述咱們如何開啓 simulation(節選):框架


經過改變 pool size,咱們能夠調節併發程度,經過控制 tick,咱們控制 traffic 的速率;經過添加更多的 simulation,咱們改變 traffic 的多樣性。

在 simulator 的做用下,很長一段時間裏,咱們的開發網絡三天兩頭 crash(崩潰) —— 一會 out of memory,一會 too many open files,一會 gen_server tiemout,一會 tcp send/receive buffer full。這些問題,若是換上個 4G memory / 4 CPU / 100G disk 的主機,只有很小的機率才暴露出來,而咱們主動讓其發生在開發環境中,使得大部分問題獲得了妥善處理。好比說,咱們發現咱們使用的 consensus engine(共識引擎) 不穩定,時不時 crash,crash 以後很容易把 state db(狀態數據庫) 寫壞,使得節點完全崩潰,沒法恢復。對此,咱們的作法是,一旦 consensus engine crash,咱們讓 Forge 自動 crash(惋惜了 erlang VM 強大的 crash recover 機制),而後由咱們開發的 forge starter 將 forge 重啓。重啓後,咱們回溯到上一個區塊的數據,從新 apply,若是 consensus engine 能夠恢復,那麼舊繼續日後走;不然便繼續 crash 和繼續回溯。

在這樣嚴苛的環境下 Forge 逐漸成長,至尊乞丐節點組成的網絡,不斷死亡,不斷重生,就像「明日邊緣」裏的湯姆克魯斯,從小白一路成長爲小強,迎來了第一百萬個 transaction。

好景不長,在大約 1.5M txs 時,網絡再次 crash:

此次 crash 的一乾二淨,全部節點全軍覆沒,連 ssh 都上不去。Digital Ocean 的監控顯示 CPU 基本爲 0,正琢磨着是否是 disk 寫滿了,一臺機器迴光返照,給我登上去 du 的機會。果真,25G 的 disk 被吃得一乾二淨。take snapshot,換大硬盤,搞定。

三月上旬咱們終於拋棄了 $5 的機器,換裝 $15 的「大」節點。在 Digital Ocean 的雲上,咱們同時跑了好幾個網絡,作 rolling upgrade。以前咱們一週一個 milestone,出一個大版本,若干小版本,三月第二週起,咱們天天出一個版本,於是,版本太多而網絡不夠用了。。。

很快,1 million txs 的里程碑被 5 million 取代:

繼而被 6M,7M,… 取代。後來咱們 breaking change 太多,也就沒有繼續累積這個數字。

可讓區塊鏈節點穩定地在 $15 的機器上部署是咱們 ArcBlock 的一個創舉。咱們作過別的公鏈的節點 —— 對方給出的推薦配置,一個節點一個月要一千多美金。若是一個應用開發者開發者,想部署一個本身的鏈,初期經過本身的節點來服務其用戶,假設節點部署在全球四個區域:每一個區域兩個節點,那單單是這樣一筆開銷,就超過上萬美金每個月 —— 沒有充沛現金的小玩家,是燒不起這個錢的。因此咱們但願這個數字可以低至幾百。

然而 Digital Ocean 畢竟是服務於小客戶的,一個嚴肅的 dApp,在開發階段使用 DO 無可厚非,在生產環境 —— 當鏈上線以後,更具實力的雲服務是更好的選擇,好比咱們本身的 ABT network 就部署在 aws。

簡約而不簡單的生產環境

因爲 ABT network 強調織鏈爲網,咱們首發三條以化學元素「氬(Argon)」「溴(Bromine)」「鈦(Titanium)」命名的元素鏈(其中 Bromine 是一條專門運行最新 nightly build 版本的測試鏈)。於是咱們須要爲這三條鏈準備安全可信的生產環境。

咱們是這樣考慮線上的生產環境的:

  1. 每條鏈都部署到亞太歐美四個區域;

  2. Argon 和 Titanium 各十六個節點;Bromine 四個節點

  3. 全部節點都只對外暴露 p2p 端口;

  4. 節點的 GraphQL RPC 和自帶的區塊瀏覽器經過 ELB 容許外部訪問,而 gRPC 只容許本地訪問;

  5. 每一個 region,每條鏈的 ELB 的域名,由 route 53 按照 latency 來 load balancing。

最重要的,要自動化,要足夠省錢。

自動化,這個不消說,咱們已經有深厚的 ansible / terraform 經驗。

省錢是個學問。

按照上面的配置,哪怕只用物美價廉的 c4.large / c5.large,每一個節點配 110G EBS,每條鏈每一個區域都配一個 ELB,一個月下來光固定成本就要 $3721。

計算公式: 0.11 (c4.large 價格) x 36 x 24 x 31 + 36 x 110 x 0.12 (EBS 價格) + 25 (ELB 價格) x 12

這其中,EC2 佔了大頭,接近 $3000。

咱們的目標,是儘量下降這個成本。

因而咱們的目光投向了 spot instance。下圖是 spot instance 在 us-east-2 和 ap-southeast-1 的價格走勢:

價格基本穩定在 on-demand instance 的 2 折,也就意味着 EC2 這塊,咱們能夠把成本降到 $600,總價只需 $1300 每個月。

然而用 spot instance,繞不過去的坎就是萬一 instance 被殺掉,如何儘快恢復服務?尤爲是驗證人節點?

咱們採用的方式是 root disk 和 data disk 分離,Forge 存儲的全部數據放 data disk,而 Forge 的配置,節點私鑰,驗證人私鑰,放 root disk,而後在初始化以後備份到一個 AES 加密的,只容許單次寫的 S3 bucket 中。以後,在節點運行的時候,每條鏈每一個區域按期備份某一個健康節點的 data disk。這樣,當驗證人節點被殺掉時,咱們能夠從最近的一個備份中恢復 data disk,而後從 S3 中找回該驗證人節點的私鑰和配置。

這個思路提及來挺簡單直觀,作起來可要頗費一番心思的。不過最終咱們趟平了這條路,證實了它是可行的,對 dApp 開發者,甚至其餘區塊鏈的同行,這種使用 spot instance 運行區塊鏈節點的方式都有借鑑意義。

最終咱們的部署腳本 forge-deploy 分紅四部分:

  1. 只須要一次性運行的腳本:好比爲每一個區域每一個 VPC 建立 security group

  2. 製做 Forge AMI 的腳本:咱們每 release 一個新的版本,都會建立一個新的 AMI。

  3. 建立一條新鏈所須要的資源的腳本:好比建立 spot request,EBS,建立 ELB,target group,設置 listener (及 listener rules),建立域名及域名解析的 policy。

  4. 管理一條已有鏈的腳本:好比初始化鏈,重啓節點,升級節點,修復損壞的節點,添加新的節點等

三月的最後兩週,forge-deploy 在原有零散腳本(部署 DO 機器的腳本)的基礎上邊開發邊測試 —— 咱們的鏈建了拆,拆了建,兩週趟過了不少區塊鏈團隊可能一年都沒有趟過的路:最多的時候咱們有 6 條鏈並行運行,算上那些朝生暮死的 abtchain,origin,bigbang,test,abc 等鏈,咱們前先後後建立了和銷燬了三十多條鏈 —— 注意,這裏說的是多區域多節點的鏈,單個節點的鏈並不包含在內。

因爲以前累積了足夠的自信,在 ABT Network 上線的那一天,咱們自負地把以前爲發佈已經建立好的三條鏈:Argon,Bromine 和 Titanium 在上線倒計時前不到半小時拆掉從新發布,讓整個團隊和社區關心咱們的人能夠看到區塊從零到一的躍遷。雖然中間有點波折 —— 部署腳本運行得比預想要慢一些 —— 於是在發佈倒計時結束後咱們尚未部署完成,但最終,耽擱了大約二十分鐘,三條鏈仍是如願上線。每條鏈的部署只須要兩條命令:

其中,create_fleet 會在四個區域裏都作這些事情:

  1. 獲取當前區域的 default VPC id

  2. 獲取 VPC 的 subnet id

  3. 獲取預先建立好的幾個 security group 的 id

  4. 用預設的配置爲驗證人節點申請 spot fleet

  5. 用預設的配置爲哨兵節點申請 spot fleet

  6. 等待全部申請好的 instance 能夠正常工做

  7. 建立 ELB

  8. 建立 target group,並將全部 instance 加入 target group

  9. 獲取預先上傳好的證書 id

  10. 建立兩個 ELB listener,80 端口直接 301 到 443,而 443 端口把流量轉發到 target group

  11. 建立 DNS 域名記錄,設置 latency based policy

當四個區域都完成以後,爲這條鏈的全部 instance 建立 ansible inventory,以便後續處理。

接下來,在 init_forge_network 裏,會作這些事情:

  1. 把 data disk mount 到對應的 instance 上,並格式化文件系統爲 XFS

  2. 使用臨時配置文件啓動 Forge,生成 node key 和 validator key

  3. 把生成的 key 備份到 S3

  4. 根據 inventory file,找出驗證人節點,將其 validator address 寫入 genesis 配置中

  5. 啓動 forge

全部節點起來後,稍候片刻,一條鏈就完美誕生了!

相關文章
相關標籤/搜索