kumo-server が全ノード WAIT になる

kumofs でサーバーを kumoctl detach した時に、kumo-server の全ノードが WAIT 状態になることがあったので調べてみました。というかここ数ヶ月ずっと調べてました。

attach, detach, replace により、kumo-server 間でデータが転送される時は次のような流れで行われます。

この例は server1 から server2 と server3 にデータを送る場合です。

    server1                   server2                   server3
       |                         |                         |
 A     |---- 送ってもいい? ---->|                         |
 B     |---- 送ってもいい? ------------------------------>|
       |                         |                         |
 C     |<------- いいよ ---------|                         |
 D     |<------------------------------- いいよ -----------|
       |                         |                         |
 E     |------ 転送開始 -------->|                         |
       |          :              |                         |
       |-------転送終了 -------->|                         |
       |                         |                         |
 F     |-------転送開始----------------------------------->|
       |          :              |                         |
       |-------転送終了----------------------------------->|
       |                         |                         |

A, B に対する応答 C, D は並列に処理されますが、データ転送 E と F はシーケンシャルに処理されます。
また、A, B 時には C, D の応答を待つためのタイマーが設定されます。デフォルトでは 1280秒*1でタイムアウトします。

通常は server1 が自分が持ってるデータのうち server2, server3 それぞれに送りたいものを /tmp*2 に抽出してから、転送を開始します。これだと大量のデータを転送する必要がある場合、かなり大きな一時ファイルが必要になってしまいます。--replace-memory-limit オプションを指定することで、指定したメモリに達する度に転送することができます。

図にするとこんな感じです。

    server1                   server2                   server3
       |                         |                         |
   (データが溜まった)            |                         |
       |---- 送ってもいい? ---->|                         |
 G     |---- 送ってもいい? ------------------------------>|
       |                         |                         |
       |<------- いいよ ---------|                         |
 H     |<------------------------------- いいよ -----------|
       |                         |                         |
       |------ 転送開始 -------->|                         |
       |          :              |                         |
       |-------転送終了 -------->|                         |
       |                         |                         |
       |-------転送開始----------------------------------->|
       |          :              |                         |
       |-------転送終了----------------------------------->|
       |                         |                         |
       |                         |                         |
   (データが溜まった)            |                         |
       |---- 送ってもいい? ---->|                         |
 I     |---- 送ってもいい? ------------------------------>|
       |                         |                         |
       |<------- いいよ ---------|                         |
       |<------------------------------- いいよ -----------|
       |                         |                         |
       |------ 転送開始 -------->|                         |
 J     |          :              |                         |
       |-------転送終了 -------->|                         |
       |                         |                         |
 K     |-------転送開始----------------------------------->|
       |          :              |                         |
       |-------転送終了----------------------------------->|
       |                         |                         |

問題は G で設定した server3 に対するタイマーが J でタイムアウトすることがあるということです。G に対する応答は H で返っているにもかかわらず、タイマーは生きたままなので、このタイムアウトを I のタイムアウトと勘違いしてしまうようです。その結果 K の処理は行われず、ログに次のように出力されます。

storage offer to server3 is already timed out

おそらく --replace-memory-limit を使用してなくても短期間に attach, detach を何回か実行した場合にも発生するのではないかと思います。


ということで、この現象に対処してみました。

https://github.com/tmtm/kumofs/commit/479e94781362d1880874c7aede16bf311c0df041

kumofs の内部構造をわかってないので上記の説明も間違ってるかもしれませんが、一応うまく動いているようです。

*1:--clock-interval オプションの値(デフォルト: 8) * 160 秒

*2:--offer-tmp オプションで変更可能