Archive for 12月 2014

トランザクションを理解する

さて、昨日書いた補足説明をしたいと思います。

まずレイドボスの場合は、倒したかどうか?という判断が必要になります。
読んでいる数値が保証されていなければどうなるか?
通常は討伐報酬が発生しますが、報酬の2重付与が発生してしまいます。
悲しい事に、ここまで書かないと何が悪いの?と理解できない人間が多いのがゲーム業界のサーバーエンジニアです。

ですから、プランナーがサーバーエンジニアをただのweb屋レベルのペチパーと勘違いするのも仕方ないと思います。
本当は数が少ないだけで、最も知識が必要で高いレベルが要求されるのがサーバーエンジニアです。
アプリ側は人間が余っていますが、マトモなサーバーエンジニア・インフラエンジニアは数が少ないのでどこの会社も人材を求めている所でしょう。

で、次に減らしてから増やすという話も説明しないと理解できない人が大勢いるでしょう。
そもそもA処理が終わってB処理が終わらない。
このシチュエーションが起こるケースは
1.トランザクションを利用していない。
2.B処理が別の保存先(例えばキャッシュ)
という事が考えられます。

もう1つ考えられる最もアホな発想についてまずは潰しておきます。
3.トランザクション中にコミットして片方が切り捨てられるという発想です。
はい、WALとか知らないんだったら勉強しましょうね。
insert文やupdate文を実行した時にそのデータはどこにいくとお考えですか?
メモリ上を更新するだけです。
そしてコミット処理を受け付けた時にmysqlが何をしているか知っていますか?
REDO(トランザクション)ログをシーケンシャルに書き出してメモリ上のデータが仮で無くなるだけです。
(設定されていればbinlogも)
binlogがredoログだと思っている人が多いですが、binlogはbinlogです。
多分レプリケーションの関係で後から付けた仕組みなんじゃないですか?>binlog
ib_logfile0とib_logfile1というのがmysqlのトランザクションログです。
チェックポイントに到達するとログファイルを切り替えて、実際にディスクに書き込むのでそれまではオンメモリなんですよ。
ですのでmysqlのリカバリのメカニズムは、ディスクに書き込まれていないデータはトランザクションログから復旧を試みます。
コミットに途中で?失敗する=トランザクションログの書き込みに途中で失敗する=mysqlサーバーのディスク逝ってるレベル。
2行目のクエリ書き込みタイミングでディスク逝く確率はゼロじゃないけど、このパターンの障害はファイルも救い出せないレベルじゃねーの?って事。
仕組みを知らずにケース3を想像してた人は、せいぜい意地になって超低確率のレアケースを想定してなさいってこった。

次にケース1
トランザクションを利用していない。>アホか、氏ね。

次にケース2
片方だけ更新しちゃう>アホか、氏ね
キャッシュだったとしても、ロールバック出来る形で実装していないのは設計が間違ってるだけ
キャッシュだったとしたら、キャッシュを消せば次回はDBから読み込んでキャッシュ化する作りになってなかったらアホ
ロールバックするの仕組みを実装するのが面倒だったら、DBへのコミット失敗したらキャッシュ消せ
つまり減らして増やすじゃなくて、DBコミット→キャッシュコミットという順番なら正しい
キャッシュコミットに失敗する=キャッシュサーバーがフェイルオーバーするから、DBから読み直して動くので全く問題なし
問題があるなら設計に問題がある、消えて困るデータをキャッシュするな

唯一筋が通りそうなのは、キャッシュじゃなくて
ケース4.垂直分割とかDBが分かれているケース
XA-TRANSACTION使えアホと言いたい所だが、Transactionマネージャーを自作するのが面倒くさいので自力Commitループしてるパターン。
このパターンだったら片方だけコミットされるというのはあり得るから、最終的にはエラーログからデータは戻すんだけど
それまでの間の問題にならないように減らす→増やすの順番でコミットせーよ!ってのは有りかもしれませんね。

ペチパー酷過ぎ

ソシャゲーというかスマホアプリ
今のクラサバ型ネイティブアプリを支えているのは、サーバーエンジニアの一部のマトモな人間だとひしひしと感じる出来事があった。
これは久しぶりにソシャゲ系の記事も書いてみようかと思うに足る衝撃である。

基本的にゲーム系で育った人間はトランザクションを理解していない人間が多いみたいである。
同じプログラムが並行で動いたら、これじゃデータおかしくなりますよね?っていうのが理解出来ていない。
これは、ソシャゲの勉強会?の資料で減らして→増やすとか意味不明な事を書いて撒き散らしてる人達も同じなんだろうと思われる。
トランザクションを使ってないか?使い方を間違えてるから、このような意味不明な事を言うのだろう。
ゲーム業界の低レベルな人間だと、一見なるほどと思ってしまうような内容ですしね。

ここら辺は業務系で育った人間の方が優秀である。
数字が狂ったら業務に支障が出て始末書物の世界なので、並行動作への教育は十分にされている。
ゲーム系のスライド等を見ても一部のマトモな人間はちゃんとread lockについて言及していますし、こういった人間が支えているんですね。
気持ちは分かるんですけど、ゲーム業界の低レベルな人間がよくやってしまうのは
更新処理の部分だけでしかbeginTransactionとcommitを考えれない。
今読んでいるデータの値が動作中に保証されている必要があるのか?まで考えが及ばない人が多いようです。

簡単に例を上げるとレイドボスのHP
現在HPを読んでHPからダメージ減算という処理があったとします。
ほぼ同時に処理が動作した時に、現在HPが同じ値を読む事があるという当たり前の事を考えられないんですよねぇ。
Aさん:ボスHP:1000、攻撃100、残りHP900
Bさん:ボスHP:1000、攻撃200、残りHP800
現在読んだデータを信用できない作り方にするのであれば、
update文では、boss_hp = boss_hp – 100
のような更新をする事でカバー出来る事があります。
レイドボスの場合は読んだデータを信用するパターンじゃないと困るケースでしょうけど。