コンピュータ同士の協業の難しさ、人間同士の協業の難しさ 〜スケールアウト、排他制御、待ち行列〜
プログラム自学案内の29回目です。今回は前回からの続きで、スケーラビリティと排他制御にまつわる考え方を紹介したいと思います。前回までの記事はこちらです。
前回の課題おさらい(同時更新問題)
まずは前回の記事で紹介した課題をおさらいします。
花子の操作 (15時14分40秒)
BEGIN;
INSERT INTO orders VALUES ('担任の先生', '卓上カレンダー', 6);
--コミット直前にquantityの合計をチェック
SELECT item, SUM(quantity) AS "合計" FROM orders GROUP BY item;
パパの操作 (15時14分50秒)
BEGIN;
INSERT INTO orders VALUES ('スナックのママ', '卓上カレンダー', 6);
--コミット直前にquantityの合計をチェック
SELECT item, SUM(quantity) AS "合計" FROM orders GROUP BY item;
COMMIT;
花子の操作 (15時15分00秒)
COMMIT;
--2人ともチェックしたはずなのに、SUM(quantity)が上限を超えてしまう
SELECT item, SUM(quantity) AS "合計" FROM orders GROUP BY item;
花子とパパは、SUM(quantity)が上限を超えないように気をつけながら、DBに行を追加します。しかし、2人ともコミットする直前にSUM(quantity)をチェックしていても、タイミングが重なってしまうと、上限を超えてしまうという問題を紹介しました。
これ、いったいどれくらい問題なのか、ピンと来づらい話ではあります。
ですが、この問題への解決案をちょっと、考えてみてください。実際、プロのIT技術者は、顧客や上司に対して、この問題にどう対処するか説明できないと、一人前とはとても言えません。
課題の解決案をいくつか
いくつかアイデアを出してみます。
案A. DBへの同時接続を許さない
登録タイミングが重なる根本原因はDBへの同時接続にありますから、それを防ぐのが有効なやりかたです。
案A.1 DBに登録できるのはパパだけにする(花子はパパにたのんで登録してもらう)
案A.2 操作できるPCを1台のみに決める
案A.3 PosgreSQLの同時接続数の上限を1にする
案B. DBへの同時接続を許し、DB内で排他制御をする
同時接続を許しながら、データの同時更新による異常を防ぐための工夫が排他制御です。
排他制御では、ある処理が、他の処理を待たせたり、手戻りさせたりする仕組みを作ることによって、データの同時更新による異常を防ぎます。
案B.1 テーブルロックによる排他制御
案B.2 レコードロックによる排他制御
案B.3 レコードの楽観的ロックによる排他制御
難しそうな言葉が出てきました。じっさい、これをやるには、けっこうアタマを使います。やり方は、あとで説明します。
案C. DBへの同時接続を許し、排他制御もしない
排他制御をしない手もあります。ただし、これだと上限を超える注文を防ぐことは出来ません。
案C.1 何も対策をうたない
案C.2 1人アタマの注文数に上限を設ける
案C.3 チェックする上限を在庫より少なめにしておく
とくに 案C.1 などは解決策ではないように感じる方もいるかもしれません。しかし、これはこれで「リスク許容」という立派な判断です。
リスクとは、起きるかも起きないかも知れない痛手のことです。案A~案Cの選択肢が突きつける判断は、リスクをどう評価するかという判断なのです。
もし、上限を超える注文が登録されてしまった場合、今回の問題では、おすそ分けの注文のキャンセルで友人の信用を失ったり、自腹でカレンダーを買うはめになります。それがどれくらいイヤかを評価することにより、課題への対応が変わるのです。こんなかんじですね。
絶対にイヤ
→ 案Aか案Bを選びます。これをリスク回避と言います。起きたら起きたでしょうがない
→ 案C.1を選びます。これをリスク保有とかリスク許容とか言います。起きるのはしょうがないけど被害を抑えたい
→ 案C.2や案C.3を組み合わせます。これをリスク低減と言います。
あなたはどれを選びますか
さて、花子とパパのケースであれば、案Aか案Cを選ぶのが常識的な判断、案Bを選ぶのは相当変わり者だと思います。
ところが、私は案Bの排他制御の技術を紹介したいのですね。
なぜなら、多くの商用システムの開発では、同時更新による異常のリスクが許容できず、かつ、DBへ同時接続させたいことがほとんどだからです。
リスクが許容できないのはわかります。でも、DBへ同時接続させたい理由は何でしょうか? それはひとえに、スケーラビリティ にあります。
スケーラビリティ・スケールアップ・スケールアウト
スケーラビリティ(scalability, 拡張可能性) とは、コンピュータシステムの性能の高めやすさのことです。システムの性能を高める方法には、二つあります。
スケールアップ
性能の良い機械にとりかえること。
スケールアウト
同じ性能の機械を増やすこと。
機械の性能には限界がありますが、同じ性能の機械は、お金を出せば出すだけ増やせる。したがって、スケーラビリティという面では、スケールアウトのほうにだいぶ分がある、と言えます。そのかわり、デメリットもあります。
スケールアウトは同時更新の問題を起こす
スケールアウトさせると、2台以上の機械が同時に動くことになります(同時に1台しか動かないのでは、機械を増やした意味がありませんので)。すると、困ったことに同時更新の問題が発生するわけです。というわけで、これから逃れるための排他制御のやりかたを知っておくのは、IT技術者としては必須なのですね。
排他制御と待ち行列
排他制御の副作用:渋滞
問題を解決するには排他制御を行うわけですが、困ったことに、排他制御は、スケールアウトで高めたはずの性能を劣化させます。なぜなら、排他制御では、一つの処理が他の処理を待たせることになるからです。
たとえ話になりますが、自動車がタクシー1台しかない村を想像してください。車が1台しかないのですから、この村には信号がありません。
さて、ここで村が豊かになり、みんなが車を買うと、みんなはすばやく移動できるようになるでしょうか。
みんなが車を買う(スケールアウトみたいなもの)
↓
交通事故が起きた(同時更新による異常発生みたいなもの)
↓
事故を防ぐために信号機を設置(排他制御みたいなもの)
↓
信号待ちが多くなり渋滞も発生
なかなかうまく行かないですねえ。この「うまく行かなさ」とどう付き合うかが、IT技術者としての腕の見せ所なのです。
待ち行列理論:待ち時間は思いのほか長い
待ち時間というのは、待たされる側は思いのほか長いのです。
待ち行列理論 というのを使えばその待ち時間を計算できます。せっかくなので、いちど計算してみて、思いのほか長いことを知っておきましょう。
たとえば 1時間に10組の来客を応対できる受付1人に対して、1時間に8組の割合で来客があったとします。受付にとっては、80%の時間しか働かなくてもすむわけで、だいぶ余裕があるように思えますが、来客は平均で何分待たされることになるでしょうか?
ここで計算できます。
https://keisan.casio.jp/exec/user/1246158568
上から順に、10、8 と入力すると 0.5 と答えが返ってきますので、待ち行列理論によると、来客は平均で30分待たされるということになるわけです。たまったもんじゃないですね。
人間社会や組織でも起きているジレンマ
さきほど村の交通や、来客の応対で例えたとおり、スケールアウトと、排他制御、待ち行列といった問題は、それに通底した課題を人間社会のいたるところで目にすることができます。
なぜなら、古来より人々は大きな仕事を、「一つの仕事を、複数人で手分けをする」というスケールアウトでこなしてきたからです(それが出来ることこそが人類の強みですね)。人類が成し遂げた大きな仕事のなかで、たった1人によりなされたものは、芸術などの限られた分野にしかありません。
人々は、スケールアウトで大きな仕事をするために、大企業を作ったり、人海戦術をとったりします。その代償として、組織の方針に一貫性をもたせようとして「意思決定の渋滞」がおきたり、「管理職」という「仕事をしていないように見える人」が必要になったりするのですね。
ソフトウェア開発の現場でのスケールアウト
よくプログラミングの分野では、並のプログラマの 10倍、100倍の仕事ができる人がいると言われます。このこと自体は正しいです。
ですが、だからと言って、「100倍の給料を出して100人力の人を雇うスケールアップ」はできないのが現実です。現実は、1倍の人を100人雇うスケールアウトを行います。
GAFAMであってもです。GAFAMの創業メンバーは100人力、1000人力の凄腕だったのかもしれません。しかし彼らは、彼ら自身の能力をさらスケールアップさせることは出来ません。代わりに、社員数をふやす、というスケールアウトをするわけです。だから、GAFAMだって、千人とか万人とかの単位で、人を雇ったり解雇したりしてるわけですよね。
スケールアウトと人月の神話
ところで、ソフトウェア開発の現場で、人をふやすスケールアウトの副作用は相当に知られたものです。それを説いた有名な本が 『人月の神話』 です。
『人月の神話』では、進捗遅延をとりもどすために要員を増やしても、むしろ進捗はより遅れてしまう、ということが説かれます。1人で10か月かけて終わる仕事を、10人でやれば1か月で終わらせられるだろうか? ことソフトウェアシステムの開発では、そんなふうにうまくはいかない。人と月の掛け算の交換法則は、成り立たないというわけです。
『人月の神話』では、人と月の掛け算の法則が成り立たない理由が、「要員間のコミュニケーション(意思疎通)にかかるコストの増加」と説明されています。このコミュニケーションは、成果物となるソフトウェアの一貫性、整合性を保つために必要なものです。排他制御の副作用に似ているとは思いませんか。
排他制御とGit
近年では、ソフトウェア開発の現場の中心には、Gitリポジトリがあります。ソフトウェア開発で生み出されるソースプログラムが格納されるGitリポジトリは、現場全員のプログラマから、更新・参照されるDBのようなものですから、まさに現場の中心です。
ところで、Git が発明される以前には、Subversion という SCM(バージョン管理ソフト) が使われていました。これが、排他制御により多くのプログラマの「待ち」「渋滞」を発生させていたのです。
Git は巧妙な仕組みで、プログラマからこの「待ち」を解放しました。交差点から信号機を取っ払ったようなものです。そのかわり、その巧妙なルールを理解できるまで、Gitは使い方が難解に見えるツールになっています。でも、その難解さに余りあるメリットがあるわけですね。
まとめと次回予告
今回の記事では、PostgreSQLによる排他制御のやり方についての紹介の前置きとして、背景として理解しておくべき、排他制御の必要性とその副作用について、人間社会にみられる現象にたとえて話をしました。
まとめると、性能を高めるためには機械の数を増やすしかない。機械を増やして無対策だと同時更新で異常(衝突)が起きる。異常を防ぐためには排他制御が必要。ただし排他制御の仕組みづくりはむずかしいうえ、渋滞を発生させ性能が悪くなる。そして、同様の問題は、一般に人間同士の協業でも起きている。というわけです。
「ぜんぜんポスグレの使い方の話を、してくれないじゃんか 前置き長げえし つまらねえよ おこ!」
ごめんなさい。でも、今回はポスグレの使いかたより大切な話をしたつもりなんです。
次回予告です。PostgreSQLによる排他制御のやり方について紹介します。気の早い人は、GoogleやChatGPTに聞いて、試してみてかまいませんよ!