コンテンツにスキップ

API サーバーのアーキテクチャ

このページは、API サーバーがネットワークリクエストをどのように AkkEngine へ対応付けるかを理解したい場合に読むページです。起動方法とクライアントからの呼び出し例は API サーバーの使い方 に分けています。

API サーバーのコードは akkara/akkserver/ にあり、AGPLv3 で別ライセンスになっています。サーバー有効ビルドを配布する場合は、この境界を確認してください。

エンジン起動時、AkkEngine::open()components.apiEnabled を確認します。有効であれば、API サーバーバックエンドを読み込むか既存の生成元を使い、設定された通信方式向けの集約サーバーを作成し、ストレージエンジン構成要素の準備が終わった後に起動します。

サーバーの寿命はエンジンの寿命に従います。AkkEngine::open() の途中で起動し、close() またはエンジン破棄時に停止します。

バックエンド役割
HTTP手元での確認、スクリプト、簡単なサービス境界。
TCP高スループットクライアント向けのコンパクトな AK5 バイナリプロトコル。
gRPCProtobuf/gRPC サポートがある場合の型付き RPC インターフェイス。

どの通信方式も、最終的には同じ AkkEngine 操作へ対応付けられます。API サーバーはスキーマ認識を追加しません。キーと値は生のバイト列のままです。

HTTP レスポンスボディは、明示的にテキストを返すエンドポイントを除き、リトルエンディアンのバイナリエンコードです。

エンドポイントボディ
/v1/exists[exists:u8]1 が存在、0 が不存在。
/v1/count[count:u64le]
/v1/scan[count:u32le][truncated:u8]{row}*
/v1/history[count:u32le][truncated:u8]{entry}*
/v1/batchGet[count:u32le]{[status:u8][value_len:u32le][value bytes]}*
/v1/statsコンパクトなリトルエンディアン形式の EngineStats スナップショット。

scan の行は次の形です。

[key_len:u16le][value_len:u32le][key bytes][value bytes]

history のエントリは次の形です。

[seq:u64le][source_node_id:u64le][timestamp_ns:u64le][flags:u32le][value_len:u32le][value bytes]

truncated1 の場合、設定値またはリクエストされた limit に到達して途中で切られています。続きが必要な場合は、limit を増やすか、後続の範囲リクエストを組み立てます。

ストリーミングボディは 5 バイトの前置きから始まります。

ストリーム前置き
scanAKKS\x01
historyAKKH\x01

chunk を展開した後のボディは、次のフレーム列です。

[frame_type:u8][payload_len:u32le][payload bytes]

フレーム種別 1 は項目です。scan の項目ペイロードは非ストリーミング scan と同じ行形式です。history の項目ペイロードは非ストリーミング history と同じエントリ形式ですが、外側の counttruncated は付きません。

フレーム種別 2 は終端フレームです。

[emitted_count:u32le][truncated:u8]

HTTP ストリーミングはサーバーからの返し方を変えるだけです。エンジン側のスナップショット意味論を変えるものではありません。

TCP 通信方式は AK5 バイナリフレームを使います。リクエストフレームは 16 バイトのヘッダーから始まります。

char[4] magic = "AK5Q"
u8 version = 2
u8 opcode
u32 request_id
u16 key_len
u32 val_len

レスポンスフレームは 13 バイトのヘッダーから始まります。

char[4] magic = "AK5S"
u8 status
u32 request_id
u32 val_len

TCP リクエストは次の形です。

[request header][key bytes][value bytes][crc32c:u32le]

リクエスト CRC32C は key bytes + value bytes を対象にします。レスポンスは次の形です。

[response header][value bytes][crc32c:u32le]

レスポンス CRC32C は value bytes だけを対象にします。

Opcode操作
0x01GET
0x02PUT
0x03REMOVE
0x04GET_AT
0x05BATCH_PUT
0x06BATCH_GET
0x07PING
0x08EXISTS
0x09COUNT
0x0ASCAN
0x0BHISTORY
0x0CROLLBACK_TO
0x0DROLLBACK_KEY
0x0EFORCE_SYNC
0x0FFORCE_FLUSH
0x10STATS
0x11SCAN_STREAM
0x12HISTORY_STREAM

status の値は次の通りです。

Status意味
0x00OK
0x01見つからない
0xFFエラー

request_id はレスポンスへそのまま返されます。1 つの接続で複数のリクエストをパイプライン処理する場合、レスポンスの対応付けに使います。

操作リクエストキーリクエスト値
GET, PUT, REMOVE, EXISTS, HISTORY対象キー操作ペイロードまたは空
GET_AT, ROLLBACK_KEY対象キー[seq:u64le]
ROLLBACK_TO[seq:u64le]
COUNTstartKeyendKey
SCANstartKey[limit:u32le][endKey bytes]limit = 0 は無制限
BATCH_PUT, BATCH_GETバッチペイロード
FORCE_SYNC, FORCE_FLUSH, STATS, PING

TCP の scan レスポンスは [count:u32le][truncated:u8]{row}* です。TCP の history レスポンスは [count:u32le]{entry}* です。HTTP history と違い、非ストリーミング TCP history には truncated バイトがありません。

SCAN_STREAMHISTORY_STREAM は、同じ request_id を持つ複数の AK5S レスポンスを送ります。各レスポンスの値が 1 つのストリームフレームです。

[frame_type:u8][payload_len:u32le][payload bytes]

フレーム種別 1 は項目、フレーム種別 2 は終端です。終端ペイロードは [emitted_count:u32le][truncated:u8] です。

gRPC 通信方式は、同じエンジン操作に対応する単項呼び出しと、scan/history 向けのサーバーストリーミング呼び出しを提供します。サービス名は akkaradb.grpcapi.v1.AkkaraDB です。

単項呼び出しは PingPutGetRemoveExistsCountScanGetAtHistoryRollbackToRollbackKeyBatchPutBatchGetForceSyncForceFlushStats に対応します。ストリーミング呼び出しは ScanStreamHistoryStream です。

gRPC はビルド構成に依存します。Protobuf/gRPC サポートがない場合、gRPC バックエンドは実際のサーバー通信方式として利用できません。gRPC には、api.grpcPortapi.grpcWorkerThreadsapi.grpcCompletionQueuesapi.grpcMinPollersapi.grpcMaxPollersapi.grpcMaxConcurrentStreamsapi.grpcResourceQuotaBytesapi.grpcMaxBatchItemsapi.grpcMaxScanItemsapi.grpcMaxHistoryEntries が反映されます。

api.transportMode == TLS の場合、gRPC は api.tls.certPathapi.tls.keyPathapi.tls.caPath を使います。api.tls.verifyPeer が true で CA パスが設定されている場合、クライアント証明書が要求されます。

オプション対象メモ
api.httpMaxBatchItemsHTTP バッチエンドポイント大きすぎるバッチボディを拒否します。
api.httpMaxScanItemsHTTP scan1 リクエストで返す、またはストリーミングする行数を制限します。
api.httpMaxHistoryEntriesHTTP history1 リクエストで返す、またはストリーミングする履歴エントリ数を制限します。
api.httpMaxContentLengthHTTP リクエストボディPOST ボディによるメモリ使用量を制限します。
api.tcpWorkerThreadsTCP0 は自動動作です。
api.tcpAcceptQueueLimitTCPワーカー待ちの受け入れ済みソケット数を制限します。
api.tcpAcceptQueueTimeoutMsTCP待ちすぎたキュー内ソケットを落とします。0 でタイムアウトを無効化します。
api.tcpPipelineBatchLimitTCPパイプライン化されたリクエストをまとめて処理する上限です。
api.tcpMaxBatchItemsTCP バッチエンドポイント大きすぎるバッチペイロードを拒否します。
api.tcpMaxPendingResponseBytesTCP/gRPCバックプレッシャー制限です。gRPC の送受信メッセージサイズにも使われます。
api.tcpReadTimeoutMsTCPアイドル状態または部分フレーム読み取りのタイムアウトです。0 で無効化します。
api.tcpWriteTimeoutMsTCPレスポンス書き込みのタイムアウトです。0 で無効化します。

ローカル開発では既定値から始めるのが自然です。制限値は、リクエストサイズ、同時接続数、レスポンスのバックプレッシャーを測ってから調整してください。