でこてっくろぐ ねお

株式会社はてなのSRE。でこらいふろぐ(http://dekolife.hatenablog.com/)の姉妹版。デコテックログ(deko tech log)である

bitcoinのfull nodeをAWSでなるべく安く運用してみる

本エントリは、bitcoinのfull nodeとは何か、なんで私は運用したいのかを簡単に説明しつつ、full nodeをできるだけAWS環境にて安価に運用する方法について記載する。

結論

だいたい以下の価格で運用可能。 bitcoinへの貢献度合いの設定によってもっと減らしたり、青天井に増やしていくことも多分可能。そのあたりはこれからの運用を通して正確なところを探っていく。

  • full node
    • 月に $16
  • full node(pruned)
    • 月に$10弱(想定)

動機

最近、"web3"ってやつが熱いと聞き、NFTやDeFiについて調べたりしたが、裏側の仕組みがよくわからないと気持ちが悪いので、ひとまず技術書を何冊か読んだ。その中の一冊に、名著と名高い"Mastering Bitcoin"を和訳した"ビットコインとブロックチェーン"という書籍も含まれる。 この書籍はbitcoinブロックチェーンがどのように実装されているかが非常に詳しく書かれており、暗号資産周りの技術的なバックグラウンドを得るための最初の一冊としてかなり良かった。その中で、bitcoinブロックチェーンを構成する重要な登場人物の一つにfull nodeがあった。

full nodeとは一体なんなのか。full nodeと同様、bitcoinの登場人物の中で、ブロックを採掘する役割の"マイナー"についてはbitcoinに詳しくない人でも聞いたことはあるのではないかと思う。かつて、私はbitcoinブロックチェーンを信頼できるものにするのに重要なのはマイナーだけだと思っていたのだが、この本を読んで、full nodeはマイナーと同じくらい重要な存在だと知った。 full nodeは、マイナーが作成したブロックの検証を行う存在であり、また、軽量クライアントと言われるクライアントに対してブロックチェーンを提供する存在でもあり、ユーザの取引をマイナーに伝える存在でもある。full nodeがいないとbitcoinブロックチェーンは成り立たない。例えば、世界に1台しかfull nodeが存在しない場合、任意のアドレスへの送付を含む取引を拒否する、任意のマイナーの発掘するブロックを拒否する、任意のマイナーの発掘する偽のブロックの検証を成功させる、等やりたい放題できてしまいbitcoinブロックチェーンの根幹が崩壊する。それだけ重要な存在ではあるが、書籍を読んで疑問に思ったのが、"マイナーは採掘すると報酬が得られるが、full nodeは重要な割には運用するインセンティブ全くなくないか?"というものだった。

そのため、私はfull nodeを運用するインセンティブについて調べ始めた。 そこで出会ったのが以下ページである。

Full node - Bitcoin Wiki

このページに、そのものずばり、 Why should you use a full node wallet という項目がある。 これを読むと、セキュリティやプライバシー的にfull nodeを使う意味があるということが書かれていたりするが、少なくともそんなに多額のbitcoinを持っているわけではない私個人としては、セキュリティやプライバシーを、取引所やハードウェアウォレットに仮想通貨を保持している今より向上するためにfull node運用をするイメージはなく、full node運用にかかるコスト次第で、bitcoinが衰退していくイメージさえ感じてしまった*1*2

多くはないがbitcoinを所持している身としては、このあたりをある程度はっきりさせておきたいのと、また、ブロックチェーンの運用に携わってみたい、という気持ちが出てきたため、full nodeを運用しつつ運用にはいくら位がかかるかを実際に作りながら考えてみることとした。

構成

クラウドにはAWSを選定している。個人的に慣れてるから以上の理由はない。構成は以下の通り。

                          Internet
                            xxxx
                        xxxxx  xxxxxx
                      xxx x         xxx
                  +---x---->Peer      x
                  |   xxxx   xx   xxxxx
                  |     xxxxxxxxxx
+---------VPC-----+----+
| +-Public Subnet-+--+ |
| |               |  | |
| |     +--EC2----++ | |
| |     |         v(port 8333)
| |     |       EIP| | |
| |     |  bitcoind| | |
| |     |          | | |
| |     +----------+ | |
| +------------------+ |
+----------------------+

public subnetのVPCにbitcoindが動いているサーバが1台。サーバにはEIPを付与*3し、他のfull nodeとのピアのためにインバウンドで8333ポートを開けている。 サーバへのログインは、AWS System Managerを使うことで外からの穴開け不要でログインを行っている。

以下のAWS CDKコードを使って構築している。

github.com

なお、このCDKのコードはEC2をstartさせるところまでしか行っておらず、bitcoindを動かすところは別のシェルスクリプトにまかせている*4。そのシェルスクリプトはこちら: https://gist.github.com/dekokun/1342c289078cb1e9b4cf6825ce5cbff9)

AWS上でコストを安くする工夫と今後の課題

  • EC2のインスタンスタイプにはt4g.microインスタンスを使用
    • bitcoindはARM用のバイナリを配布しているため、Graviton2を使うことでEC2にかかるコストを下げることができる
    • 運用中にかかる負荷は平均して10分に1度のブロック採掘の際の検証が一番大きいが、t4g.microでもCPUは十分に耐えられるレベルである。一番のネックはメモリ量だと考えられる。適切に設定をするとt4g.nanoでも運用に耐えられそうではあるが、それは今後の課題である
  • EBSにはSC1(Cold HDD)を使用
    • prunedではない*5full nodeを運用する場合、全部で450GBほどのディスクを消費するため、ディスクにかかるコストを下げる恩恵は大きく、SC1を選定
    • 幸い、定常運用時にはほとんど中身の変化はなく、また、古いデータに対するアクセスの頻度も低い*6ため、SC1(Cold HDD)でも全く問題なく運用が可能
    • なお、SC1はroot filesystemには使えないので別途root filesystemに使うdiskは必要
    • (2021/12/30 追記) SC1は実はburstableで、bitcoindを運用して数日経つとI/Oのburstが尽きて採掘スピードにブロックの検証が間に合わなくなっていくことがわかった。現在は、burstが尽きる度にEC2を stop && start してburst balanceを復活させて対応している(restartでは回復しないことに注意)
      • その後bitcoinのパラメータをチューニングし、maxuploadtarget=1024にすると、I/O burst がギリギリ切れないくらいで推移することがわかった。
  • コンテナ化しない
    • コンテナ化した場合、例えばNLB + Fargate Spot + EFSの構成が考えられるが、Fargate Spotの1vCPUあたりの価格(1時間$0.01544723)がt4g.microの価格(1時間$0.0084)を大きく越えており、また、EFSの価格(1月1GB $0.36)もEBS(SC1)の価格(1月1GB $0.018)と比較すると大きく*7、更にNLBにかかるコストだけで、上記EC2の構成のコストを超えてしまうため、以下の通りコンテナ化のメリットもそこまで大きくないため採用しなかった
      • bitcoinのfull nodeは常に動き続けることが重要なわけでなく、例えば"落ちてアラートが鳴ったので1日以内に対応する"くらいの温度感で特に問題はないため、オートヒーリング的なものの嬉しさがそこまで大きくない
      • 平均10分に1度のブロック採掘を定常的にさばきつつ、できる範囲でpeerをはっている別ノードの要求に応えていれば良いため、あまり大きくアクセス傾向などが変化することもなく、柔軟性を得ることの嬉しさがそこまで大きくない
  • サーバレス化はしない
    • コスト的には上記の通り、NLBの最低金額だけでEC2構成の金額を越えてしまう
    • そもそもの問題として、本当にサーバレス化が可能なのかどうかがわかっていないというものがある。NLBの裏にbitcoinクライアントlambda(ストレージにEFSを使用)をぶら下げることでもしかすると可能なのかもしれないが、今後の課題である

bitcoind初回起動時の問題について

上記は定常運用時の構成の話である。実は上記の構成ではbitcoinのfull nodeの初回起動時は何日経ってもfull nodeは定常状態にならず起動シーケンスがひたすら続くことになる。そのあたりの話を書く。

bitcoinのfull nodeの運用を行うにおいて、避けては通れない道がある。それは、IBD(initial block download)と呼ばれる、これまでのすべてのbitcoinの取引台帳を検証しつつ手元にダウンロードしていく作業である。full nodeが独立してブロックを検証するのはブロックチェーンが信頼たるものになるために比較的重要な機能なのでここを飛ばすことはできない*8IBDをある程度現実的な時間で実行するためには、運用時とは異なるコストが初期費用としてのってくる。bitcoinクライアントのリファレンス実装であるbitcoindを立ち上げると、最初にIBDが始まり、全データをダウンロードしながらの全ブロックの検証が始まる。 現在、bitcoinの台帳は全部で350GB程度である。幸い、AWSのinternet gatewayは、アウトバウンドのトラフィックにはコストがかからない*9。 ここで、ブロックの検証として行われていることは様々である*10が、特に処理として重いのは、各取引に含まれるインプットが参照しているアウトプットの検証*11部分だと思っている。

この検証のためには、対象の取引に含まれるインプットをこれまでの未使用の取引のアウトプットすべてから検索する必要がある。検証に使用する未使用の取引のアウトプットのデータは数GBあり、それがメモリに乗らないとディスクI/Oが大量に発生し検証が非常に遅くなるため、ある程度メモリが多いインスタンスを使用するのが望ましい。

私は最初t4g.small(メモリ2GB) + EBS(SC1)のサーバを使っていたが、全713000ブロックを検証する必要があるのに10分で80ブロックしか検証が進まず、運用開始までに2ヶ月ほどかかる感じがしたのでおとなしくインスタンスタイプをt4g.large(メモリ8GB)に上げることで10分で10000ブロックの検証が行えるようになった*12。100倍以上の高速化である。

また、メモリを増やした状況でEBS(SC1)を使っていると致命的な問題があった。それはbitcoindを落とした時の挙動である。bitcoindを落とすとキャッシュをディスクに書き戻すが、それがいつまで経っても終わらずにsystemdに設定してある TimeoutStopSec=600 を越えてしまって強制的にプロセスが殺され、その後立ち上げると Rolling forward 000000000000000000113c66910d73d8986d86d114b6dd47b24ae826c2ded1e7 (554566) というようなログが出て、これは何かわからないが多分キャッシュを書き戻せなかった分の再検証を行っている?1時間で166ブロックほどしか進まずにいつまで経っても起動する気配がなくなった。bitcoindを落とさなければこのようなことは起きないし、TimeoutStopSecをinfinityにするなどでも回避できるとは思う*13が、最初の運用開始の際の試行錯誤の段階ではそれも難しいと思うので諦めてEBS(GP3)でIBDを終わらせてからEBS(SC1)に切り替えるのが良いだろう。私はそうした。 こうすることで、IBDが1日以内に終わった。

コストと要件のトレードオフ

安全面などを考えると、本当はbitcoindの動くEC2はprotected subnetに置き、inboundをNLB経由で受け取りたいところだが、protedted subnetにインスタンスを置くことで発生するNAT Gateway及びNLBにかかるコストで一気に金額が5倍近くになるため今回は採用していない*14。 private subnetに置いた状態でも、例えばログインしたい時以外はNat Gatewayを落とすなどすることでコストを減らすことも可能ではあるが、運用が煩雑である。

また、現在は東京リージョンを使用しているが、別のリージョンを使用することで何割か削減可能である。

このあたりはセキュリティや利便性・コストとの兼ね合いとなる。

実際にかかっているコスト計算

初期費用(IBDにかかる費用)

IBDに1日かかるとした際の計算。以下、計$3 - EC2(t4g.large) - 0.0864 * 24 = $2.0736 - EBS(gp3 500GB)(本来はスループット課金なども考える必要があるが面倒なので割愛。多分無料分に収まっている) - 0.096 * 500 / 31 = $1.54

運用費用(月額)

以下、計$15。 実際はアウトバウンドのトラフィックやroot EBSにかかるコストも存在するが、以下と比べると非常に微々たるものなので記載しない。

  • EC2(t4g.micro)*15
    • 0.0084 * 24 * 31 = $6.2496
  • EBS(SC1 500GB)
    • 0.018 * 500 = $9
    • full nodeをpruned modeで動かすことで、ブロックの保管に必要な容量を90%以上削減可能なようなので、ここはもっと下げることが可能(今回検証はしていない
  • (2022/01/14 追記) 実はここに記載の料金以外に、何も設定しないとoutboudの料金が1日最大$10 ほどかかる(peerをはる相手によってはもっとかかるだろう)ことがわかった。 maxuploadtarget=1024 にすることで、1日$0.20ほどですむようになった。もっと減らせばもっとお金もかからなくなるだろう
    • 0.2 * 31 = $6.2

感想

最初は"ディスクに500GBも必要だと、月間数千円かかるなぁ"と思っていたが、EBSのSC1が安すぎて思ったよりもかなり安く上がった。これなら個人で運用可能。また、CPUに必要な要件がここまで下がると、コンテナ化やサーバレス化を検討する際にNLBがネックになってコストが上がってしまうということもよくわかった。あと、よく言われる話ではあるがNAT Gatewayが高い。 ただ、今の構成でもやはりある程度はかかるので以下のようなことは検討していきたい。

  • AWS以外のクラウドを使用してのfull node運用
  • node運用にインセンティブのあるnodeの運用
    • こちらは、そもそもbitcoin以外のものを使う、ということでこのエントリの趣旨とは根本的に異なってくるが

ここに書いた内容は技術的には一切新規性はないが、bitcoinのfull nodeを作りたいと思った人が実際にどれくらいの金額や構成や時間で構築可能なのかを知る目的では非常に有用なのではないかと思っている。

今後の暗号資産との向き合い方

今回の記事に書いた内容は、冒頭に記載した"web3をやりたい"というところからは大きくハズレており、次の一歩はもう少しそれっぽいことをしようということで、ひとまずスマートコントラクトを知るために"マスタリング・イーサリアム"を読んでいる。やっていくぞ!DeFiへの道はまだ遠い!!!

この記事は はてなエンジニア Advent Calendar 2021の17日目の記事です。昨日は id:kouki_danGitHub Actionsで次のリリースにどんな変更が含まれるかを可視化する - Lento con forzaでした。明らかに便利そう。使いたい。 明日は id:onk です!

*1:なお、 https://bitcoinmagazine.com/business/bitnodes-project-issues-first-incentives-node-operators-1426544155 にも同様の危機意識が書かれており、これによれば、かつてインセンティブが払われていた時期もあるようだ

*2:なお、 Bitcoin Network 365-day Charts - Bitnodes を見ると、実際にはfull nodeの数は徐々に増えていることが分かる。マイナーや事業者が増えてるから、ということなんでしょうねぇ

*3:実際のところIPが変わってもfull node運用という点で大きな問題はないと思っているのでEIPは必須ではないかと思っているが、IPを固定しておくと https://bitnodes.io/nodes/leaderboard/ のリーダーボードのランキングが上がっていくので楽しい。EIPを1つEC2にアタッチする分には無料だし

*4:cdkでcloudformation initを使いCDKに組み込みたかったが、このエントリをアドベントカレンダーの締め切りまでに書くために間に合わなかったので諦めた

*5:prunedなfull nodeというものが存在する。このfull nodeはブロックを検証した後に古いブロックは破棄して新しいブロックのみを保持することでfull nodeと大体同等の機能を提供しつつディスク使用量を大幅に削減するもの。今回はひとまずprunedは使わなかった

*6:なんらかの方法でS3をバックエンドにするともっとコストが下げられるのではないかということも考えられるが今後の課題である。pruned nodeの存在や、SC1の圧倒的なコストの低さのため、モチベーションはそんなに高くはないが

*7:今みたら、EFSには低頻度アクセスストレージというものがあってこちらは結構安いのでディスクはもしかしたらEFSでも遜色ない値が出るかもしれない

*8:実はEthereumの有名クライアントのGethでは"fast sync"モードというのがあり、初回起動時の完全なトランザクションの検証をスキップしている(ブロックヘッダの検証はしている様子)ので、"飛ばすことはできない"というのも結局程度問題ではある

*9:実はわたしは初回起動時は今とは構成が異なり、Nat Gatewayの下で行ったため、$20ほどかかってしまったのだが…更にいうとHDDとSSDでのIBDの速度を比べようと2台でIBDをしていたため計$40かかってしまった〜

*10:詳細はbitcoindのCheckBlock関数を参照すべし: https://github.com/bitcoin/bitcoin/blob/master/src/validation.cpp#L2995]

*11:bitcoinの持つ台帳は取引ごとにインプットとアウトプットが存在し、新たな取引は別の取引の未使用のアウトプットを参照しなければならない。詳細は書籍"ビットコインブロックチェーン"参照

*12:"bitcoin IBD slow"などでgoogle検索すると、未使用の取引のアウトプットデータ(UTXOという)をキャッシュするためのdbcacheパラメータを変更すると良い、となっていたためt4g.largeにした後にdbcache=3000(単位はMiB。デフォルトは450)に設定してみたが、私の環境ではそんなに違いを感じられなかった。OSのディスクキャッシュで十分だったのだと思われる

*13:その場合は、プロセス停止までにどれくらい時間がかかるのか検証できておらず全くわからないという別の問題が出てくる

*14:正確には、最初はその構成で構築していたがIBDが終わったあたりでやめてpublic subnet上でsnapshotからEC2を作り直し運用を開始した

*15:実はcost explorerを確認してもこのコストが確認できずEBSのコストだけが記載されている。AWS Free Tierページにも記載がないので無料枠を使ってるわけでもなさそうなのだがどういうことなのだろうか。一ヶ月ほど様子を見てみておかしかったらサポートに問い合わせてみる