昨天,也就是 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 版本的測試鏈)。於是咱們須要爲這三條鏈準備安全可信的生產環境。
咱們是這樣考慮線上的生產環境的:
每條鏈都部署到亞太歐美四個區域;
Argon 和 Titanium 各十六個節點;Bromine 四個節點
全部節點都只對外暴露 p2p 端口;
節點的 GraphQL RPC 和自帶的區塊瀏覽器經過 ELB 容許外部訪問,而 gRPC 只容許本地訪問;
每一個 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 分紅四部分:
只須要一次性運行的腳本:好比爲每一個區域每一個 VPC 建立 security group
製做 Forge AMI 的腳本:咱們每 release 一個新的版本,都會建立一個新的 AMI。
建立一條新鏈所須要的資源的腳本:好比建立 spot request,EBS,建立 ELB,target group,設置 listener (及 listener rules),建立域名及域名解析的 policy。
管理一條已有鏈的腳本:好比初始化鏈,重啓節點,升級節點,修復損壞的節點,添加新的節點等
三月的最後兩週,forge-deploy 在原有零散腳本(部署 DO 機器的腳本)的基礎上邊開發邊測試 —— 咱們的鏈建了拆,拆了建,兩週趟過了不少區塊鏈團隊可能一年都沒有趟過的路:最多的時候咱們有 6 條鏈並行運行,算上那些朝生暮死的 abtchain,origin,bigbang,test,abc 等鏈,咱們前先後後建立了和銷燬了三十多條鏈 —— 注意,這裏說的是多區域多節點的鏈,單個節點的鏈並不包含在內。
因爲以前累積了足夠的自信,在 ABT Network 上線的那一天,咱們自負地把以前爲發佈已經建立好的三條鏈:Argon,Bromine 和 Titanium 在上線倒計時前不到半小時拆掉從新發布,讓整個團隊和社區關心咱們的人能夠看到區塊從零到一的躍遷。雖然中間有點波折 —— 部署腳本運行得比預想要慢一些 —— 於是在發佈倒計時結束後咱們尚未部署完成,但最終,耽擱了大約二十分鐘,三條鏈仍是如願上線。每條鏈的部署只須要兩條命令:
其中,create_fleet 會在四個區域裏都作這些事情:
獲取當前區域的 default VPC id
獲取 VPC 的 subnet id
獲取預先建立好的幾個 security group 的 id
用預設的配置爲驗證人節點申請 spot fleet
用預設的配置爲哨兵節點申請 spot fleet
等待全部申請好的 instance 能夠正常工做
建立 ELB
建立 target group,並將全部 instance 加入 target group
獲取預先上傳好的證書 id
建立兩個 ELB listener,80 端口直接 301 到 443,而 443 端口把流量轉發到 target group
建立 DNS 域名記錄,設置 latency based policy
當四個區域都完成以後,爲這條鏈的全部 instance 建立 ansible inventory,以便後續處理。
接下來,在 init_forge_network 裏,會作這些事情:
把 data disk mount 到對應的 instance 上,並格式化文件系統爲 XFS
使用臨時配置文件啓動 Forge,生成 node key 和 validator key
把生成的 key 備份到 S3
根據 inventory file,找出驗證人節點,將其 validator address 寫入 genesis 配置中
啓動 forge
全部節點起來後,稍候片刻,一條鏈就完美誕生了!