豪鬼メモ

一瞬千撃

DBサービスを作ろう その12 非同期レプリケーションのプロトコルと実装

データベースサーバの非同期レプリケーション機能を実装したが、そのプロトコルと実装の詳細について述べつつ、妥当性について検証しよう。非常に細かくて重箱をつつく話になるが、神は委細に宿るとも言うし、ないがしろにできないことばかりだ。
f:id:fridaynight:20210930205558p:plain

続きを読む

DBサービスを作ろう その11 非同期レプリケーション完成!

ついに、データベースサーバTkrzw-RPCに非同期レプリケーション機能がついた。マスタ・スレーブ構成だけでなく、デュアルマスタ構成もサポートして、オンラインシステムのバックエンドとして利用できる高可用性を備えたシステムになった。Tkrzw-RPC-0.9.0から利用できる。
f:id:fridaynight:20210925210207p:plain

続きを読む

DBサービスを作ろう その10 更新ログによるインクリメンタルバックアップ

Tkrzw-RPCのレプリケーション機能を実現するために、Tkrzw本体に更新ログ機能をつけた。更新ログ機能は任意のコールバックを呼び出す実装になっていて、それにメッセージキューを接続すると、マルチリーダで任意の後処理ができるようになる。今回は、メッセージキューのレコードとして保存した更新ログを使って、ローカル環境でインクリメンタルバックアップを実現する方法について説明する。
f:id:fridaynight:20210917232201p:plain

続きを読む

DBサービスを作ろう その9 更新ログのメッセージキュー化

前回の記事で、レプリケーション機能の実装を見越して、データベースの更新ログ機能を設計した。実装を進めながら思ったのは、データベースに更新があった旨をログとして記録して、またそれを外部に通知するという動作は、メッセージキューと同じ要件を持つということだ。よって、汎用メッセージキューを実装して、それを更新ログに流用するように設計を見直す。その方が機能性も上がるし、テストもしやすい。

続きを読む

DBサービスを作ろう その8 レプリケーションを踏まえた更新ログの要件

データベースの堅牢性を高めるために、データベース本体とは別に更新内容を保存する、更新ログという手法がある。さらに、更新ログを逐次別サーバに転送して適用すれば、レプリケーションが成立する。この記事では、レプリケーションにも使える更新ログの要件についてまとめる。

続きを読む

DBサービスを作ろう その7 シャーディング最強説

シャーディングによってデータベースを分割することで、通常運用の並列処理性能を向上させることができる。それだけでなく、バックアップ作成などの、他のスレッドをブロックさせうる操作の影響を最小限に留めることができる。その運用方法について説明する。

続きを読む

キャストに関わるGCCの謎挙動

GCCの不可解な挙動に悩まされている。以下のコードは、負数を出力しないことが期待されるが、-O2以上の最適化をすると負数が出力されてしまう。

#include <cstdint>
#include <cstdio>

int main(int argc, char** argv) {
  constexpr uint32_t modulo = 2039;
  for (int32_t i = 0; i < 65536; i++) {
    const int32_t result = static_cast<uint32_t>(i * i) % modulo;
    std::printf("%d\n", result);
  }
  return 0;
}

上記で、i の値が46340を超えると、i * i の値がint32_tの範囲をオーバーフローして負数になる。その直後にuint32_tにキャストされると正数に変換され、その後に2039で割った余りになるので、結果は0から2038の間になるはずだ。それをint32_tにキャストしてもオーバーフローはしないはずだ。-O0と-O1では期待通りに動作する。しかし、-O2以上の最適化をすると、負数が生成される。-O2以上の最適化をする場合も、変数moduloの宣言にvolatileをつけると負数は生成されない。

gccのバージョンはgcc (Ubuntu 10.3.0-1ubuntu1~20.10) 10.3.0だ。バグなのか、仕様上で未定義の挙動を引き起こす記述をしてしまっているのか、わからない。キャストが無視されているのはアセンブリ出力を見るまでもなく明らかなのだが、なぜそうなるのかというか、仕様通りなのかどうかが知りたい。「最適化によってキャストが無視されることがある」という事実を認めるとすると、どのような場合にそれが起こるのか知っておかないと安心して暮らせないだろう。ご存知の人がいたら教えてほしい。

続きを読む

DBサービスを作ろう その6 非同期化による性能向上

前回の記事にて、バッチ化とストリーム化によってgRPCの性能が向上することを示した。残る高速化の手段は、非同期APIを利用することである。結論としては、サーバ側では非同期APIを利用すると性能がかなり向上する。これを実装したTkrzw-RPC 0.7.1をリリースしたので、お試しいただきたい。

この記事では、同期APIと非同期APIの性能測定をして、非同期APIの優位性を示す。また、C++の非同期APIの解説がネット上にあまりに少なかったので、実装の進め方を詳細にメモしておく。

f:id:fridaynight:20210905220104p:plain

続きを読む

DBサービスを作ろう その5 バッチ化とストリーム化による性能向上

前回の記事で述べた性能評価によって、gRPCによる操作が同一マシン上なら2万QPSのスループットで実行できることが分かった。これはデータベース自体の性能に比べると遅すぎるので、より高いスループットが出せるようにgRPCの使い方を工夫したくなる。今回は、バッチ化とストリーム化を行ってどの程度性能が向上できるかを確かめた。
f:id:fridaynight:20210903032228p:plain

続きを読む