
2026/01/14 2:55
**Show HN: Ayder – HTTP ネイティブで耐久性のあるイベントログ(C で実装、cURL をクライアントに使用)**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
(Ayderは、JVMやZooKeeperに依存せず単一バイナリで実行できるC言語で書かれた軽量でHTTPネイティブな耐久イベントログ/メッセージバスです。Raftコンセンサスを用いて3/5/7ノードクラスター間の高可用性レプリケーションを実現し、非同期、同期マジョリティ、および同期全体という3種類の書き込みモードに対応しています。フォロワーはHTTP Locationヘッダー経由でリーダーへリダイレクトされます。
実際のネットワーク環境で動作した3ノードクラスターでのベンチマークでは、約50 kメッセージ/秒のスループットとサブミリ秒級のサーバーレイテンシ(P99.999 ≈ 1.22 ms)が確認されました。8 Mオフセットを持つ不正終了からの回復は40〜50秒で完了し、データ損失はありませんでした。Snapdragon X Eliteノートパソコン(WSL2)上でARM64テストを実施した結果、106 kメッセージ/秒のスループットとDigitalOcean VMよりも低いレイテンシが達成されました。
APIは純粋なHTTP/RESTです。curlで直接呼び出せ、ペイロードはバイナリ安全なBase64エンコードされています。エンドポイントには
/topics、/produce、/consume、/commit、/delete-before、KVストア、および組み込みのストリーム処理(フィルタリング、集計、ウィンドウジョイン)があり、Avro+Protobufなど複数フォーマットをサポートしています。
デプロイメントオプションとしては、Prometheus/Grafanaモニタリング付きDocker Composeスタック、単一バイナリビルド、またはソースコンパイル(
libuv 1.51+、OpenSSL、zlib、liburingが必要)があります。HAクラスターの設定は環境変数(RF_HA_ENABLED、RF_HA_NODE_ID、RF_HA_NODES、RF_HA_WRITE_CONCERNなど)で行い、RaftトラフィックにはmTLSもサポートしています。
AyderはMITライセンスの下で公開されており、カザフスタン出身のソロ創業者Aydarbek Romanulyによって開発されました。)
Text to translate
(incorporating missing details and removing unsupported extrapolation):**
Ayder is a lightweight, HTTP‑native durable event log/message bus written in C that runs as a single binary without JVM or ZooKeeper dependencies. It uses Raft consensus for high‑availability replication across 3/5/7 node clusters and supports three write modes—async, sync‑majority, and sync‑all—with followers redirecting to the leader via an HTTP Location header.
Benchmarks on a real‑networked 3‑node cluster show ~50 k messages per second throughput, sub‑millisecond server latency (P99.999 ≈ 1.22 ms), and recovery from an unclean shutdown in 40–50 seconds for 8 M offsets—no data loss. ARM64 tests on a Snapdragon X Elite laptop (WSL2) achieved 106 k msg/s throughput with lower latency than DigitalOcean VMs.
The API is plain HTTP/REST; curl works directly, and payloads are binary‑safe base64 encoded. Endpoints include
/topics, /produce, /consume, /commit, /delete-before, a KV store, and built‑in stream processing (filtering, aggregation, windowed joins) with cross‑format support (Avro+Protobuf).
Deployment options comprise Docker Compose stacks featuring Prometheus/Grafana monitoring, a standalone binary build, or source compilation (requiring
libuv 1.51+, OpenSSL, zlib, liburing). Configuration for HA clusters is done via environment variables (RF_HA_ENABLED, RF_HA_NODE_ID, RF_HA_NODES, RF_HA_WRITE_CONCERN, etc.) and supports mTLS for Raft traffic.
Ayder is licensed under MIT and was authored by Aydarbek Romanuly, a solo founder from Kazakhstan.
本文
Ayder
HTTP ネイティブで永続性のあるイベントログ/メッセージバス – C で書かれています
curl がクライアントになる、単一バイナリのストリーミングシステム。JVMも ZooKeeper も厚いクライアントライブラリも不要です。
▶️ 1 分デモ: SIGKILL → 再起動 → データはそのまま
https://www.youtube.com/watch?v=c-n0X5t-A9Y
Produce
curl -X POST 'localhost:1109/broker/topics/orders/produce?partition=0' \ -H 'Authorization: Bearer dev' \ -d '{"item":"widget"}'
Consume
curl 'localhost:1109/broker/consume/orders/mygroup/0?encoding=b64' \ -H 'Authorization: Bearer dev'
なぜ Ayder なのか?
| 機能 | Kafka | Redis Streams | Ayder |
|---|---|---|---|
| プロトコル | バイナリ(厚いクライアント) | RESP | HTTP (curl が使える) |
| 耐久性 | ✅ 再複製ログ、非同期レプリケーション | ⚠️ 非同期のみ、クォーラムなし | ✅ Raft コンセンサス(同期多数) |
| 運用 | ZooKeeper/KRaft + JVM チューニング | 単一ノードまたは Redis Cluster | 単一バイナリ、依存性ゼロ |
| レイテンシ (P99) | 10–50 ms | N/A(非同期のみ) | 3.5 ms |
| 復旧時間 | 2+ h(クリーンでないシャットダウン) | 分単位 | 40–50 s |
| 最初のメッセージ | 約30分セットアップ | 約5分 | 約60秒 |
Kafka は実績がある一方、運用コストが高い。Redis Streams はシンプルで高速だが非同期レプリケーションしか提供しない。Ayder はその中間に位置し、Kafka レベルの耐久性(Raft 同期多数)と Redis のような単純さを兼ね備えています。
何が得られるか
- パーティションごとのオフセット付き append‑only ログ
- コミット済みオフセットを持つコンシューマーグループ
- シールされた append‑only ファイル(AOF)による耐久性とクラッシュリカバリ
- Raft コンセンサスによる HA レプリケーション(3/5/7 ノードクラスター)
- CAS と TTL を備えた KV ストア
- フィルタ、集計、ウィンドウ付きジョイン(Avro+Protobuf など複数フォーマット対応)のストリーム処理
パフォーマンス
すべてのベンチマークは実際のネットワークで行われました。数字はマーケティングではなく真実です。
本番ベンチマーク – 3 ノードクラスター(DigitalOcean、8 vCPU AMD)
| メトリック | クライアント側 | サーバー側 |
|---|---|---|
| スループット | 49 871 msg/s | — |
| P50 | 1.60 ms | — |
| P99 | 3.46 ms | — |
| P99.9 | 12.94 ms | — |
| P99.999 | 154.49 ms | 1.22 ms |
サーバー側の P99.999 の内訳:
- ハンドラ: 1.22 ms
- キュー待ち: 0.47 ms
- HTTP パース: 0.41 ms
スループットテスト – wrk
(最大スループット)
wrk| メトリック | 値 |
|---|---|
| スループット | 93 807 msg/s |
| P50 | 3.78 ms |
| P99 | 10.22 ms |
| Max | 224.51 ms |
ARM64 ベンチマーク – Snapdragon X Elite (WSL2)
| メトリック | クライアント側 | サーバー側 |
|---|---|---|
| スループット | 106 645 msg/s | — |
| P50 | 3.57 ms | — |
| P99 | 7.62 ms | — |
| P99.999 | 250.84 ms | 0.65 ms |
サーバー側の P99.999 の内訳:
- ハンドラ: 0.65 ms
- キュー待ち: 0.29 ms
- HTTP パース: 0.29 ms
復旧時間
| シナリオ | Kafka | Ayder |
|---|---|---|
| クラスター再起動(クリーンでない) | 2+ h(本番報告) | 40–50 s |
| ブローカー同期失敗後の修復 | 1 TB データで 181 min | 秒単位で自動追いつき |
| 50+ブローカーのローリングリスタート | 2+ h(各ブローカー 2 min) | N/A – 単一バイナリ |
クラッシュリカバリをテスト:
- フォロワーを
。SIGKILL - リーダーは継続、フォロワーはオフセットを失う。
- フォロワー再起動 → ローカル AOF を再生し、リーダーから欠損データを要求、40–50 s で追いつく(データロスなし)。
クイックスタート
Docker(最速)
git clone https://github.com/A1darbek/ayder.git cd ayder docker compose up -d --build # Prometheus + Grafana も含む
スタンドアロン
docker build -t ayder . docker run -p 1109:1109 --shm-size=2g ayder
トピックを作成:
curl -X POST localhost:1109/broker/topics \ -H 'Authorization: Bearer dev' \ -H 'Content-Type: application/json' \ -d '{"name":"events","partitions":4}'
メッセージを公開:
curl -X POST 'localhost:1109/broker/topics/events/produce?partition=0' \ -H 'Authorization: Bearer dev' \ -d 'hello world'
ソースからビルド
依存ライブラリ: libuv 1.51+, OpenSSL, zlib, liburing.
make clean && make ./ayder --port 1109
Docker Compose スタック
docker-compose.yml は次を起動します:
- Ayder (ポート 1109)
- Prometheus (ポート 9090、メトリクス収集用)
- Grafana (ポート 3000、デフォルトパスワード: admin)
API 参照
ヘルス & メトリクス
| エンドポイント | メソッド | 説明 |
|---|---|---|
| GET | |
| GET | |
| GET | Prometheus フォーマット |
| GET | HA クラスターのメトリクス |
トピック管理
作成
POST /broker/topics Body: {"name":"events","partitions":8} Response: {"ok":true,"topic":"events","partitions":8}
Produce(本文は生バイト)
POST /broker/topics/{topic}/produce Query: partition (optional) key (URL‑encoded, optional) idempotency_key (URL‑encoded, optional) timeout_ms (optional) timing=1 (optional) Response: { "ok": true, "offset": 123, "partition": 0, "batch_id": 9991, "sealed": true, "durable": true, "mode": "sealed", "synced": true }
重複検知(
idempotency_key が一致した場合):
{"ok":true,"offset":123,"partition":0,"sealed":true,"synced":null,"duplicate":true}
Batch produce (
NDJSON – 行ごとにメッセージ)
POST /broker/topics/{topic}/produce-ndjson Response: { "ok": true, "first_offset": 1000, "count": 250, "partition": 0, "batch_id": 424242, "sealed": true, "durable": true, "mode": "sealed", "synced": false }
Consume
GET /broker/consume/{topic}/{group}/{partition} Query: offset (inclusive, defaults to last committed) limit (default 100, max 1000) encoding=b64 (binary‑safe base64) Response: { "messages": [ {"offset":0,"partition":0,"value_b64":"aGVsbG8=","key_b64":"a2V5"} ], "count":1, "next_offset":1, "committed_offset":0, "truncated":false }
Commit
POST /broker/commit Body: {"topic":"events","group":"g1","partition":0,"offset":124} Response: { ... }
削除・保持
先頭オフセット以前を削除(ハードフロア):
POST /broker/delete-before Body: {"topic":"events","partition":0,"before_offset":100000} Response: {"ok":true,"deleted_count":12345,"freed_bytes":987654}
保持ポリシー設定:
{"topic":"events","partition":0,"ttl_ms":60000,"max_bytes":104857600} // TTL + サイズ上限 {"topic":"*","ttl_ms":300000} // すべてのトピックに TTL
KV ストア
Put
POST /kv/{namespace}/{key}?cas=<u64>&ttl_ms=<u64> Body: raw value bytes Response: {"ok":true,"cas":2,"sealed":true,"durable":true,"mode":"sealed","synced":true,"batch_id":123}
Get
GET /kv/{namespace}/{key} Response: {"value":"<base64>","cas":2}
Delete
DELETE /kv/{namespace}/{key}?cas=<u64> Response: {"ok":true,"deleted":true,"sealed":true,"durable":true,"mode":"sealed","synced":false,"batch_id":456}
ストリーム処理
別サービス不要で組み込み済み。
- 行フィルタ(eq, ne, lt, gt, in, contains)
- 集計付き group by(count, sum, avg, min, max)
- フィールド投影
- タンブリングウィンドウ
- ウィンドウ付きジョイン(二つのソース間):
- ジョイントタイプ: inner / left / right / full
- 複合キー
- ウィンドウサイズ & 遅延許容
オプションdedupe_once- Avro + Protobuf を跨ぐフォーマットサポート
HA クラスタリング
3、5、7 ノードのクラスターを Raft レプリケーションでサポート。
書き込みモード
| モード | 確認 |
|---|---|
| async | リーダーがローカルに書き込み、バックグラウンドでレプリケーション |
| sync‑majority | 多数(例: 2/3 ノード)を待つ |
| sync‑all | すべてのノードを待つ |
書き込みはリーダーへ行う必要があります。フォロワーに送られた場合、HTTP リダイレクトでリーダーアドレス(
Location ヘッダー)を返します。
フォロワー復旧: ローカル AOF を再生し、リーダーへ接続して欠損オフセットを要求、データストリームで追いつく。自動追いつき。
実行方法
単一ノード
./ayder --port 1109 # デフォルトポート # カスタムポートの場合 ./ayder --port 7001
HA クラスター(3/5/7 ノード)
環境変数を設定:
| 変数 | 説明 |
|---|---|
| HA モード有効化 (1) |
| ユニークノード ID |
| クラスター構成: |
| 初期リーダーのみ 1 に設定 |
| 待機ノード数 (1=リーダーだけ, 2=多数, N=全員) |
| P99 レイテンシ最適化のため 0 推奨 |
| Raft の mTLS 有効化 (1) |
, , | TLS パス |
| HTTP 認証トークン () |
例:3 ノードセットアップ
# Node 1 (ブートストラップリーダー) export RF_HA_ENABLED=1 export RF_HA_NODE_ID=node1 export RF_HA_BOOTSTRAP_LEADER=1 export RF_HA_NODES='node1:10.0.0.1:7000:100,node2:10.0.0.2:8000:50,node3:10.0.0.3:9000:25' export RF_HA_WRITE_CONCERN=2 # sync‑majority (2/3) export RF_HA_DEDICATED_WORKER=0 export RF_BEARER_TOKENS='dev@scope:token2:token3' export RF_HA_TLS=1 export RF_HA_TLS_CA=./certs/ca.crt export RF_HA_TLS_CERT=./certs/node1.crt export RF_HA_TLS_KEY=./certs/node1.key ./ayder --port 7001 # Node 2 & 3 はポートと証明書を変えて同様に設定
作者 & ライセンス
開発者: Aydarbek Romanuly – カザフスタン出身のソロ創業者
GitHub: https://github.com/A1darbek/ayder
メール: aidarbekromanuly@gmail.com
ライセンス: MIT
エラーレスポンス例
一貫したフォーマット:
{ "ok": false, "error": "missing_topic", "message": "Topic name is required", "docs": "https://ayder.dev/docs/api/produce" }
Ayder は何か
- ✅ HTTP ネイティブなイベントログ(パーティションとオフセット付き)
- ✅ ポインタベースの消費で高速書き込み
- ✅ クラッシュリカバリ付き耐久性
- ✅ Raft レプリケーションで水平スケーリング可能
- ✅ クロスフォーマットジョインを備えた組み込みストリーム処理
- ✅ ARM64 ネイティブ(Snapdragon X Elite でテスト済み)
Ayder は何ではない (まだ)
- ❌ Kafka プロトコル互換性
- ❌ SQL データベース
- ❌ クライアント側の idempotency discipline が無い Magic exactly‑once