🕶️🚲 470(ヨンナナマル)くん
ヨットの帆なのに、陸で三輪車を漕いでいるこのブログの案内役です。今回も、わからないとテルテールがバタバタします。
連載「妖怪ウォッチの『カセット抜き増殖』から学ぶ分散システム」
- 第1部 なんで2台の交換は壊れるの?(噛み砕き)
- 第2部(この記事) AWS も銀行も50年前の通信も、同じことで悩んでた(大学レベル+実務)
- 第3部 今、3DS の交換を作り直すなら(応用)
第1部では、妖怪ウォッチの交換中にカセットを抜くと妖怪が増える話から、こんなことを考えました。
| 第1部でわかったこと | |
|---|---|
| 片方だけ終わる | 2台の 3DS はセーブが別々なので、片方だけ書き終わる瞬間がある |
| 消える・増える | 先に渡せば消えて、先に受け取れば増える |
| うまくいかない手 | 「せーので同時」も「確認し合ってから」も、うまくいかない |
| おあずけ札 | 「おあずけ札」を貼ってから送れば、増えない代わりに待たされる |
でも、これって妖怪ウォッチだけの悩みなんでしょうか。通信で何かをやり取りしている所なら、どこでも同じことが起きそうじゃないですか。
🤔 これって、妖怪ウォッチだけの悩み?
調べてみたら、やっぱりでした。50年以上前の通信から、今の AWS や銀行まで、みんな同じことで悩んでいました。
この記事でわかること
- 第1部で出てきた話の、正式な名前
- 昔の通信、AWS、銀行、PayPay が、同じ問題をどう扱っているか
- 僕の3つ目の勘違い
銀行や決済サービスの中身は、ほとんど公開されていません。この記事で書くのは、公式ドキュメントや公開資料、障害の報告から分かる範囲だけです。
1. 50年前から、みんな同じことで悩んでた
第1部で、「確認し合っても終わらない」問題には名前がある、と書きました。その名前の前に、昔の人たちがこの問題とどう付き合ってきたかを見てみます。
電報:中身を読み上げて確かめる
アメリカの電報会社 Western Union には、料金を半額分足すと、届いた電報の文面を送った局へ打ち返して、送った文面と突き合わせてもらえるサービスがあったそうです。1919年の裁判の判決に、その約款が引用されています。
妖怪で言うと、交換したあとに相手に「今受け取ったの、このレア妖怪だよね?」と読み上げてもらう感じです。
ただ、これが守っていたのは文字化けみたいな**「中身の間違い」**で、二重に届くのを防ぐものではありません。
1969年:0と1の印で「送り直し」を見分ける
コンピュータ同士を回線でつなぐ研究が進んでいた1969年、イギリスの研究所の3人が、短い論文で面白い方法を出しています。
| やること | 中身 |
|---|---|
| 印を付ける | 送るメッセージに、0 か 1 の印を1つだけ付けて、交互に切り替えていく |
| 「受け取ったよ」 | 相手から返ってくる印が変わったら、それが「受け取ったよ」の意味になる |
| 送り直しを見分ける | 前と同じ印のメッセージがまた来たら、それは送り直しだと分かるので、2回目は捨てる |
妖怪で言うと、交換のたびにメダルを表、裏、表……と交互にひっくり返して渡す感じです。さっきと同じ向きで来たら「これ、さっきのやつだな」と分かります。
ちなみにこの論文、同じ雑誌の号で「同じ方法を別の人たちも独自に考えていた」と書かれていて、誰が最初とは言い切れないらしいです。
1970年:返事には返事を返さない
インターネットの前身の ARPANET では、データを中継するコンピュータが、次のコンピュータから「受け取ったよ」が来るまでデータを持ち続けて、来なければ 100 ミリ秒くらいで送り直していました1。
面白いのは、論文にはっきり、返事には返事を返さない(Acknowledgments themselves are not acknowledged)と書いてあることです。
第1部で、確認し合うと最後の1通が誰にもわからなくて終わらない、という話をしました。ARPANET はそこに入っていかずに、こうしていました。
- 返事が来なければ、送り直す
- 送り直しで2回届いた分は、受け取った側が番号を見て捨てる
確認を終わらせようとするんじゃなくて、送り直しても壊れない形にしていたんです。
1974年〜:番号をもっと大きく
今のインターネットの土台になった TCP の元の論文(1974年)は、送るデータに通し番号を振って、受け取った側がもう受け取った番号を捨てるようにしました。論文には、送り直すなら受け取る側が2回目を見分ける手段が必ず要る、という趣旨のことが書かれています。
そして1975年:確認の往復には名前がついた
第1部の「確認し合っても終わらない」問題は、1975年の通信の設計についての論文に原型があるとされていて、1978年に**「二人の将軍問題」**という名前がついたそうです2。
谷を挟んだ2人の将軍が、使いを走らせて「同時に攻めよう」と約束しようとするけど、使いが捕まるかもしれないので、何往復しても安心できない、という話です。第1部の僕と相手の 3DS と、同じ形ですよね。
年表にすると
| 年 | 何が起きた | 妖怪で言うと |
|---|---|---|
| 遅くとも1919 | 電報の照合(文面を打ち返して確かめる) | 受け取った妖怪を読み上げてもらう |
| 1969 | 0/1 の印で送り直しを見分ける | メダルを交互にひっくり返して渡す |
| 1970 | 返事に返事を返さない、番号で2回目を捨てる | 送り直しは気にせず、図鑑の番号で2回目を捨てる |
| 1974 | 通し番号で、重複・抜け・順番を直す | 交換に通し番号を振る |
| 1975・1978(とされる) | 二人の将軍問題 | 第1部の「確認の往復」 |
2. 第1部の話に、名前をつける
ここからは、第1部で妖怪の言葉で話したことに、分散システムの正式な名前をつけていきます。
片方だけ止まる:部分故障
1台の 3DS なら、止まるときは全部いっしょに止まります。2台だと、片方だけ止まることがあります。この「全体のうち一部だけが止まる」ことを、部分故障といいます。分散システムが難しい理由のほとんどは、ここから来ています。
消える側、増える側、ちょうど1回
第1部の2つのパターンにも、近い名前があります。ケンブリッジ大学の Kleppmann という先生の講義ノートでは、送り方を3つに分けています。
| 名前 | やり方 | 起きうること | 第1部で言うと |
|---|---|---|---|
| at-most-once(多くても1回) | 返事が来なくても送り直さない | 届かずに終わることがある | 「先に渡したら消える」(パターン1)に近い側 |
| at-least-once(少なくとも1回) | 返事が来るまで送り直す | 2回届くことがある | 「先に受け取ったら増える」(パターン2)に近い側 |
| exactly-once(ちょうど1回) | 送り直しつつ、受け取った側が「これはもう処理した」と見分けて2回目を捨てる | ― | ― |
図にすると、ちょうど1回はこうなります。返事が消えて僕が送り直しても、相手は取引番号を見て2回目を捨てるので、レア妖怪は1体しか増えません。
ここで大事なのは、ちょうど1回というのは「通信がちょうど1回届く」じゃなくて、**「何回届いても、結果が1回分になる」**ということです。
通信をちょうど1回届けるのは無理なので、結果のほうをちょうど1回にしているんですよね。ARPANET や TCP がやっていたのも、これです。
何回やっても1回分:冪等性
第1部でも少し出てきましたけど、「何回やっても、1回やったのと同じ結果になる」性質を、**冪等性(べきとうせい)**といいます。
| 操作 | 2回やると | 冪等? |
|---|---|---|
| 妖怪図鑑に「レア妖怪を見つけた」と登録する | 何回やっても、図鑑は1つ埋まるだけ | ⭕ 冪等 |
| 手持ちに妖怪を1体増やす | 2回やったら2体増える | ❌ 冪等じゃない |
交換を冪等にするには、「この取引番号の交換は、もう終わってるか」を覚えておいて、2回目なら何もしないようにします。第1部のおあずけ札の取引番号は、このためのものでした。
返事が来ないのは、止まったから? 遅いから?:僕の勘違い③
第1部で、僕の勘違いを2つ紹介しました(光の速さと時計のズレ)。実はもう1つあります。
調べ始めたころ、僕は「FLP 不可能性定理(1985年)によると、1台でも止まる可能性があるなら、100%確実に合意する方法は数学的に存在しない」と理解していました。だから、カセット抜きは数学の限界を突く行為なんだ、と。
これも、半分違いました。
FLP 不可能性定理が言っているのは、「相手が止まったのか、ただ遅いだけなのかを見分ける手段がまったくない世界では、いつか必ず結論を出す、とは保証できない」ということです。
妖怪で言うと、返事が来ない相手が、カセットを抜かれたのか、通信が遅いだけなのか、僕の 3DS には見分けられない。だから「いつまで待てば必ず決着がつく」とは言えない、という話です。
でも、データが食い違わないこと(正しさ)まで諦めろ、とは言っていません。 今よく使われている Raft という合意のやり方の論文には、正しさは時間に頼ってはいけない(safety must not depend on timing)とはっきり書かれています。タイムアウトは、話を先に進めるためだけに使う。
| 僕が最初に思ってた | 実は | |
|---|---|---|
| FLP 不可能性定理 | 100%確実に合意する方法は数学的に存在しない | 「いつか必ず結論を出す」とは保証できない。正しさは守れる |
諦めるのは正しさじゃなくて、「必ず終わること」のほうだったんです。
第1部のおあずけ札が「増えない代わりに待たされる」だったのも、まさにこれでした。
幹事を立てても、幹事が倒れたら止まる:2相コミット
「2台で決めるからダメなんでしょ? 3台目の幹事役を立てればいいじゃん」という方法もあります。2相コミットといって、データベースでは昔からある方法です。
- 幹事が2人に「交換の準備できた?」と聞く
- 2人とも「できたよ」と答えたら、幹事が「じゃあ確定して」と号令をかける
ここで、2人が「できたよ」と答えた直後に、幹事の 3DS のカセットが抜かれたらどうなるか。
2人は、自分だけで「確定する」「やめる」を決められません。勝手に決めたら、もう1人と食い違うかもしれないからです。なので、幹事が戻ってくるまで待ち続けます。
ここでよく誤解されるんですけど、2相コミットは幹事が倒れても、データが食い違うわけじゃありません。止まって待たされる。 これも、正しさを守る代わりに待たされる、という形です。
カセット抜きは「故障」じゃなくて「ズル」
最後に、大事な区別をしておきます。故障にはいくつか種類があります。
| 故障の種類 | どうなる? |
|---|---|
| 止まったら、それっきり | ― |
| 止まるけど、あとで戻ってくる | セーブは残っている |
| 決まりどおりに動かない | 嘘をついたり、わざと変なことをしたりする |
カセット抜き自体は、止まる故障を人がわざと起こしている形です。でも、遊んでいる人はその気になれば、第3部で出てくるセーブの書き戻しみたいな、3つ目のズルもできてしまいます。
ネットのゲームの作り方を解説した有名な記事には、「プレイヤーはズルをしようとする、と最悪を想定しておけ」「ゲームの状態はサーバーだけが管理する」と書かれています。通信を信用しないだけじゃなくて、相手の端末も信用しない、ということです。
3. 実務①:AWS は「2通届く前提」で作る
ここからは、実際のシステムがどうしているかを見ていきます。まずは AWS の公式ドキュメントです。
この章のコードは、AWS 公式の Python ライブラリ(boto3)で書いたものです。本物の AWS にはつながずに、moto(AWS の偽物を PC の中で動かす道具)に向けて実際に動かしました。moto が真似していない所(時間の期限など)は、AWS の公式ドキュメントに書いてあることとして分けて書いています。
AWS の資料を読んで分かったのは、どこにも「絶対に重複しない」とは書いていなくて、**重複を捨てるのはいつも「決まった時間の間だけ」「決まった条件のときだけ」**だということでした。
やり直しは、1か所で、間を空けて、ずらす
交換に失敗したとき、僕も相手も相手の兄弟も、全員で一斉に「もう1回!」と連打したらどうなるか。
AWS の資料には、5段の仕組みがそれぞれ3回ずつやり直すと、一番奥のデータベースには 243 倍の負荷がかかる、という例が出てきます(3×3×3×3×3)。
なので AWS は、やり直すのは1か所だけにして、やり直すたびに待ち時間を伸ばして、さらに待ち時間を少しずつランダムにずらすよう勧めています。全員が同じ瞬間にやり直さないようにするためです。
「まだ手元にいるときだけ渡す」「全部か、何もしないか」
AWS のデータベース(DynamoDB)には、こんな書き方があります。
| 書き方 | 妖怪で言うと | 注意 |
|---|---|---|
| 条件付きで書く | 「このレア妖怪がまだ僕の手元にいるときだけ渡す」。2回目は、もういないので失敗する | ― |
| まとめて書く | 「僕から消す」と「相手に足す」を1つにまとめて、両方成功するか、両方やめるか | 最大 100 件まで |
| 整理番号 | 同じ番号で何回送っても1回分の結果になる | 番号が効くのは、最初の依頼が終わってから 10 分だけ |
「まだ僕の手元にいるときだけ渡す」は、コードにするとこうなります。
ddb.update_item(
TableName="Yokai",
Key={"yokai_id": {"S": "rare-0721"}}, # どの妖怪の行か
UpdateExpression="SET #o = :to", # 持ち主を B に書き換える
ConditionExpression="#o = :from", # ただし、今の持ち主が A のときだけ
ExpressionAttributeNames={"#o": "owner"},
ExpressionAttributeValues={":from": {"S": "A"}, ":to": {"S": "B"}},
…
)
-
UpdateExpressionが「どう書き換えるか」、ConditionExpressionが「どんなときだけ書き換えるか」です。 - 条件を確かめるのと書き換えるのを、DynamoDB が一度にやってくれます。なので、「確かめた」と「書いた」の間に、ほかの頼みが割り込むことはありません。
-
#oや:fromは、あとから名前や値を差し込むための空欄です。{"S": "A"}のSは「文字列」という意味です。
moto で動かしてみると、1回目は成功して、同じことをもう一度頼むと ConditionalCheckFailedException(条件に合わなかった)というエラーになりました。2回目は、もう持ち主が B だからです。
「僕から消す」と「相手に足す」をまとめるほうは、こうです。
ddb.transact_write_items(
ClientRequestToken="trade-No.0721", # 整理番号
TransactItems=[
{"Update": {…僕の手持ちを -1。ただし 1体以上あるときだけ…}},
{"Update": {…相手の手持ちを +1…}},
],
)
2つの書き換えを、両方やるか、両方やめるかにします。ClientRequestToken が整理番号で、公式ドキュメントでは「同じ番号なら、10 分の間は2回目を書かない」とされています。
moto はこの整理番号の動きを真似していなくて、同じ番号で2回頼むと、もう一度実行しようとしました(条件に合わず失敗)。なので、整理番号の効き目は、僕は動かして確かめられていません。10 分の話は公式ドキュメントの記述です。
手紙は2通届く前提で、受け取る側が見分ける
AWS のメッセージを受け渡すキュー(SQS)は、普通のものだと同じメッセージが2回届くことがあって、AWS 自身が「受け取る側を冪等に作ってね」と書いています。順番を守るタイプ(FIFO)は同じ番号のメッセージを捨ててくれますが、それも 5 分の間だけです。
FIFO で同じものを捨ててもらうには、送るときに番号を付けます。
sqs.send_message(QueueUrl=fifo, MessageBody="GIVE レア妖怪 No.0721",
MessageGroupId="player-A", # 同じグループの中は順番どおり
MessageDeduplicationId="trade-No.0721") # 同じ番号の手紙は1通にまとめる
moto で、普通のキューに同じ手紙を2回出すと2通届いて、FIFO に同じ番号で2回出すと1通だけ届きました。ただ、普通のキューの「1回しか出していないのに2回届く」は、AWS の中でコピーが何台ものサーバーに置かれることから起きるもので、moto では再現できません。5 分の期限も、moto では確かめていません。
受け取る側に「処理済みノート」を持たせる道具(Powertools)もあって、標準だと記録は 1 時間で消えます。1回目の処理が終わる前に同じものが来たら、「今やってるところ」というエラーを返します。
Powertools は、関数の上に札を1枚付けるだけで使えます。
@idempotent_function(data_keyword_argument="trade", persistence_store=store, config=config)
def give(trade):
… # 交換の処理
store は「ノートをどこに置くか」で、今回は DynamoDB にしました。config では「取引番号のところを見て、同じ依頼か決めてね」「同じ番号なのに妖怪が違ったらエラーにしてね」の2つを指定しています。moto で動かすと、同じ取引番号で2回呼んでも中身は1回しか動かず、2回目は1回目の結果が返ってきました。同じ番号で妖怪を変えるとエラー(2つ目の指定のおかげ)に、1回目の途中で同じ依頼が来ても「今やってるところ」のエラーになりました。
| 仕組み | 重複を捨ててくれる時間 |
|---|---|
| DynamoDB の整理番号 | 10 分 |
| SQS の FIFO | 5 分 |
| Powertools の処理済みノート | 1 時間(標準) |
途中で失敗したら、逆順に取り消す
AWS が公式に紹介しているやり方に、Saga があります。
| 順方向 | 注文 → 在庫を減らす → 支払い |
|---|---|
| 途中で失敗したら(逆順に取り消す) | 支払いの取り消し → 在庫を戻す → 注文の削除 |
ただ、取り消しが終わるまでの間、途中の状態が他の人から見えてしまうので、AWS は**「処理中」の印**を付けるよう勧めています。これ、第1部のおあずけ札とほぼ同じ考え方ですよね。
なお、Amazon 自身が「うちの注文はこう作っている」と説明した公式資料は見つからなかったので、ここに書いたのは「AWS が勧めている作り方」です。
4. 実務②:銀行は「お知らせ」と「精算」を分ける
次は銀行です。こっちは中身がほとんど公開されていないので、公開資料と障害の報告から分かる範囲で書きます。
振込は、2本の道でできている
日本の銀行同士の振込は、全銀システムという仕組みが中継しています。1973年から動いていて、1日に約 843 万件を扱っているそうです(2025年12月時点)。
面白いのは、振込が2本の道でできていることです。
| 道 | 中身 |
|---|---|
| お知らせの道 | 「A銀行のこの口座から、B銀行のこの口座へ」という電文を、全銀センターが中継する |
| お金の精算の道 | 銀行同士のお金の受け渡しは、日本銀行にある各銀行の口座で行う。1件1億円以上は1件ずつその場で、1億円未満は「払った分と受け取った分の差」だけを、毎日 16 時 15 分にまとめて精算する |
妖怪で言うと、交換の「渡したよ」のお知らせを先に届けて、メダルの実物の受け渡しは放課後にまとめてやる感じです。払いすぎないように、銀行ごとに上限額と担保(あずけておくお金)も決まっています。
二重に送らない仕組みは、公開されていない
全銀システムが同じ電文をどう見分けているかは、公開資料には書かれていませんでした。
ただ、手がかりはあります。2023年10月に全銀システムで大きな障害が起きたあと、運営している全銀ネットは、再発防止策の1つとして**「送り漏れと二重発信を確かめる訓練」**を新しく行う予定だと報じられています。動かしている側も、緊急時には「漏れ」と「二重」の両方が起きうると見ているのかもしれません。
利用者側のルールにも、同じ考え方が出てきます。セブン銀行のネット取引の規定には、「返事が決まった時間内に来なければ取り消し扱い。成功したかどうかは明細で確かめて」と書いてあります。
分からなければ取り消す。でも、取り消しも失敗する
ATM で、引き出しの途中に通信が切れたらどうするか。カード決済の国際規格では、結果が分からない取引は取り消しのお知らせを送って元に戻す、とされています3。インドの中央銀行は、「お金が引き落とされたのに現金が出なかった」ときは5日以内に自動で戻すよう決めていて、遅れたら1日 100 ルピーを銀行がお客さんに払うそうです。
でも、取り消しも失敗することがあります。 2021年2月のみずほ銀行の障害では、カードや通帳が ATM に取り込まれ、取り消しの処理まで失敗したそうです。取り込まれたのは 5,244 件と報じられています。
銀行で起きた「パターン2」
一番第1部に近いのが、2011年3月のみずほ銀行の障害です。振込が処理されずにたまってしまい、入金漏れを怖がって、自動処理と手作業の両方で入金した結果、「念のための二重入金」が約 1000 件起きたと報道されています。
消えるのが怖くて、増えるほうを選んでしまう。 第1部のパターン2(先に受け取る側)と似た形が、銀行でも起きていました。
海外の送金は「重複かも」の印を付けるだけ
国際送金の SWIFT には、送り直すときに**「これ、さっきのと同じかも」という印**を付ける仕組みがあります。でも、本当に重複かを判断するのは受け取った側で、自動で消してくれるわけではないそうです。
5. 実務③:PayPay と Stripe は「お店の番号」で見分ける
最後に、決済サービスです。
PayPay のお店向けの仕組みでは、お店が支払いごとに merchantPaymentId という番号を付けます。同じ番号でもう一度送られてきたら、PayPay は前回の結果を返すだけで、2回目の支払いはしません。
ただし、時間切れで返事が来なかったときは、「結果は不明」として扱って、状態を問い合わせるよう求めています。送り直す前に「今どうなってる?」を確かめる、ということです。
アメリカの決済サービス Stripe も、同じ考え方で Idempotency-Key という番号を使っています。番号は少なくとも 24 時間覚えていて、同じ番号の依頼がまだ処理中なのにもう一度来たら、「まだ処理中」というエラーを返します。
この Idempotency-Key は、ネットの標準を決める IETF で規格にしようとしている途中で、2026年10月時点でもまだ草案です。PayPay はこのヘッダーではなく、お店が付ける番号で見分けています。
| 何で見分ける? | 覚えている期間など | |
|---|---|---|
| PayPay | お店が付ける番号(merchantPaymentId) |
返事が来なければ、まず状態を問い合わせる |
| Stripe | Idempotency-Key |
少なくとも 24 時間。処理中の重複はエラー |
| IETF の規格 |
Idempotency-Key ヘッダー |
2026年10月時点で草案 |
Stripe の公式ライブラリで書くと、番号はこう付けます。
client.v1.payment_intents.create(
params={"amount": 500, "currency": "jpy"}, # 500円の支払い
options={"idempotency_key": "trade-No.0721"}, # 整理番号
)
本物の Stripe にはつながずに、PC の中に立てた偽のサーバーへ向けて動かしてみました。偽のサーバーは、1本目の頼みにだけわざと返事をしません。ライブラリには「通信に失敗したら2回まで自分で送り直して」(max_network_retries=2)と設定しています。
| 試したこと | 送られてきた Idempotency-Key
|
|---|---|
| 番号を自分で付けた | 最初の1本も、送り直しの1本も trade-No.0721
|
| 番号を付けなかった | ライブラリが自分で番号を作り、最初の1本と送り直しの1本で同じ番号 |
ライブラリが自分で作る番号は、その1回の頼みの中だけのものだと考えられます(コードを読んでの推論で、試してはいません)。アプリが落ちて起動し直したら、もう覚えていない。だから本当に守りたいなら、取引番号から番号を作って、自分でセーブしておくのが良さそうです。第1部のおあずけ札で、取引番号をカセットにセーブしていたのと同じですよね。24 時間覚えている、処理中ならエラー、の2つは偽のサーバーでは確かめられないので、公式ドキュメントの記述です。
1969年の 0/1 の印が、今は**「お店が付ける番号」や「24 時間覚えておく番号」**になっているわけです。
6. 話し合わなくても合体できるもの、できないもの
最後に、ちょっと違う方向の話です。
Notion や Figma みたいなアプリは、オフラインで編集しても、あとでつないだら合体してくれますよね。前に僕も「なんで Notion や Figma はオフラインで動くのに、交換はダメなの?」って疑問に思ったことがありました。
分けて考えると、こうなります。
| 例 | なぜ? | |
|---|---|---|
| ⭕ 合体できるもの | メモに文章を書き足す、図鑑に見つけた妖怪を登録する | こういう「増える一方」のものは、各自が勝手にやっても、あとで足し合わせれば同じ結果になります |
| ❌ 合体できないもの | 「世界に1体しかいないレア妖怪を渡す」「残高をマイナスにしない」 | こういうものは、他の誰かが同じことをしていないかを確かめないと、正しく判断できません |
これには理論の裏付けもあって、カリフォルニア大学バークレー校の研究者たちが、**「話し合い(協調)なしで正しく合体できるのは、増える一方の処理だけ」**という定理(CALM 定理)を示しています。別の研究では、「残高を0以上に保ったまま減らす」ような処理は、話し合いなしでは守れない、と整理されています。
ちなみに、Notion や Figma が実際に何を使っているかも調べてみました。
| アプリ | 方式 |
|---|---|
| Figma | 本物の CRDT(勝手に編集しても合体できるデータの作り方)ではなく、サーバーが最終的に決める方式だと、Figma 自身が書いています |
| Notion | オフライン用に指定したページだけ、CRDT に切り替えるそうです |
| Google ドキュメント | 2010年の公式ブログでは、OT という別の方式だと書かれていました4 |
定理が例に挙げているのは残高や「同じ番号は1つだけ」のような話ですけど、世界に1体のレア妖怪を渡すのも同じ形だと考えられます。ということは、**レア妖怪の交換は「話し合いが要る側」**なので、オフラインで勝手にやって、あとで合体、はできない。第1部のおあずけ札が、最後に必ず相手と答え合わせしていたのは、そのためでした。
まとめ
第2部のまとめ
- 第1部の話には名前がある。片方だけ止まる=部分故障、先に渡して消える=at-most-once、先に受け取って増える=at-least-once、確認の往復=二人の将軍問題。
- ちょうど1回は、通信を1回にするのではなく、送り直し+番号で2回目を捨てて「結果を1回分」にすること(冪等性)。50年前の通信から、今の AWS・PayPay・Stripe まで同じ形。
- FLP 不可能性定理が諦めさせるのは正しさではなく、「必ず終わること」。2相コミットも、幹事が倒れたら食い違うのではなく止まる。
- 銀行は、お知らせと精算を分け、分からなければ取り消し、あとで突き合わせる。それでも障害時には二重も漏れも起きている。
- 「世界に1体」や「残高」は、話し合いなしには守れない。だから最後に答え合わせが要る。
僕の学び
大きなインフラであっても、根本的な問題として、システムは必ず障害を起こしちゃう。なので、いつかそれを完璧に対策する、っていうのは難しいんだなぁと思いました。
特に、札を付けたり中央サーバーを用意したりしても、どれかが崩れるかもしれない。それに、毎日、毎分、毎秒、大量の処理をしているということは、それなりにやっぱり障害も起きちゃうんですよね。インフラって大変だなぁと思いました。
ちなみに僕はみずほ銀行じゃなかったので、障害は受けなかったです。障害を受けてお金が増えていればよかったなぁ(笑)。
これで、妖怪ウォッチ以外の実際の現場でどうしているかは、語れたかなと思います。
🕶️🚲 テルテール、ピシッと風に乗りました。
次は、僕が実際に妖怪ウォッチを今作り替えるならこうする、というのを第3部で紹介したいと思います。ぜひ見ていてください。
連載「妖怪ウォッチの『カセット抜き増殖』から学ぶ分散システム」
- 第1部 なんで2台の交換は壊れるの?(噛み砕き)
- 第2部(この記事) AWS も銀行も50年前の通信も、同じことで悩んでた(大学レベル+実務)
- 第3部 今、3DS の交換を作り直すなら(応用)
参考にした資料(クリックで開く)
通信の歴史
- Hartness v. Western Union Telegraph Co., 99 S.E. 759(1919)https://hallapproved.com/sc/cases/supreme/1919/4123787/
- K. A. Bartlett, R. A. Scantlebury, P. T. Wilkinson, "A note on reliable full-duplex transmission over half-duplex links", CACM 12(5), 1969 https://www.site.uottawa.ca/~bochmann/CSI5174/CourseNotes/Literature/Bartlett%20-%20alternating%20bit%20protocol.pdf
- F. E. Heart ほか, "The interface message processor for the ARPA computer network", AFIPS SJCC 1970(再録)https://tcm.computerhistory.org/ComputerTimeline/Chap24_arpa_CS2.pdf
- V. Cerf, R. Kahn, "A Protocol for Packet Network Intercommunication", IEEE Trans. Commun., 1974 https://pages.cs.wisc.edu/~pb/740/CK74.pdf
- RFC 793(1981)https://www.rfc-editor.org/rfc/rfc793.txt
- 二人の将軍問題の由来(二次資料)https://cs.yale.edu/homes/aspnes/pinewiki/TwoGenerals.html
理論
- M. Kleppmann, Distributed Systems 講義ノート(Cambridge, 2021/22)https://www.cl.cam.ac.uk/teaching/2122/ConcDisSys/dist-sys-notes.pdf
- M. Fischer, N. Lynch, M. Paterson, "Impossibility of Distributed Consensus with One Faulty Process", JACM 1985 https://groups.csail.mit.edu/tds/papers/Lynch/jacm85.pdf
- D. Ongaro, J. Ousterhout, "In Search of an Understandable Consensus Algorithm"(Raft)§5.6 https://raft.github.io/raft.pdf
- J. Gray, L. Lamport, "Consensus on Transaction Commit"(MSR-TR-2003-96)https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-2003-96.pdf
- J. Hellerstein, P. Alvaro, "Keeping CALM" https://arxiv.org/abs/1901.01930
- P. Bailis ほか, "Coordination Avoidance in Database Systems", PVLDB 8(3), 2014 http://www.vldb.org/pvldb/vol8/p185-bailis.pdf
- G. Gambetta, "Client-Server Game Architecture" https://www.gabrielgambetta.com/client-server-game-architecture.html
AWS
- Timeouts, retries, and backoff with jitter https://builder.aws.com/content/3EumjoZascWd1oZiEgL8ORlv3qE/timeouts-retries-and-backoff-with-jitter
- DynamoDB TransactWriteItems https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html
- DynamoDB 条件式 https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ConditionExpressions.html
- SQS 標準キュー https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues-at-least-once-delivery.html
- SQS 重複排除 ID https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagededuplicationid-property.html
- Powertools for AWS Lambda(Python)Idempotency https://docs.aws.amazon.com/powertools/python/latest/utilities/idempotency/
- Saga パターン(Step Functions)https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/saga-orchestration.html
銀行
- 全国銀行協会「全銀システム」https://www.zenginkyo.or.jp/abstract/efforts/system/zengin-system/
- 日本銀行「教えて!にちぎん」https://www.boj.or.jp/about/education/oshiete/kess/i27.htm
- クラウド Watch(2023-12-04)https://cloud.watch.impress.co.jp/docs/news/1551602.html
- セブン銀行 取引規定 第7条 https://www.sevenbank.co.jp/policy/rules/pdf/rule_01_01.pdf
- インド準備銀行 通達 RBI/2019-20/67 https://www.rbi.org.in/Scripts/NotificationUser.aspx?Id=11693
- 金融庁 みずほ銀行への業務改善命令(2021-11-26)https://www.fsa.go.jp/news/r3/ginkou/20211126/20211126.html
- CIO Japan(2025-09-16)https://www.cio.com/article/4056611/
- J-CAST ニュース(2011-03-24)https://www.j-cast.com/2011/03/24091266.html
- Microsoft「SWIFT System Trailers」https://learn.microsoft.com/en-us/biztalk/adapters-and-accelerators/accelerator-swift/system-trailers
動かしたライブラリ(実行は PC の中だけ)
- boto3 1.42.97、moto 5.1.22、aws_lambda_powertools 3.23.0、stripe 16.1.0(Python 3.14.10)
決済・同時編集
- PayPay Open Payment API https://www.paypay.ne.jp/opa/doc/v1.0/webcashier
- Stripe「Idempotent requests」https://docs.stripe.com/api/idempotent_requests
- IETF draft-ietf-httpapi-idempotency-key-header-08 https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/
- Figma「How Figma's multiplayer technology works」(2019)https://www.figma.com/blog/how-figmas-multiplayer-technology-works/
- Notion「How we made Notion available offline」(2025)https://www.notion.com/blog/how-we-made-notion-available-offline
- Google Drive Blog「Working together, even apart」(2010)https://idl.uw.edu/future-scholarly-communication/files/2010-GoogleDocs-OT.pdf


