Nginxのhttp2の設定項目にhttp2_streams_index_sizeがある。直感的には分かりにくかったのでちょっと調べる。
そのほかのパラメータは過去に書いたとおり、「Nginx 1.9.4 HTTP/2パッチのconf パラメータ設定項目」
streams_index配列
各ストリームに関する情報はngx_http_v2_node_s構造体によって管理されています。例えばストリームID(sid)、weight、parentといった情報を持ちます。
このngx_http_v2_node_s構造体の配列がstreams_indexです。streams_index配列は、ストリームIDからそのストリームを管理しているngx_http_v2_node_s構造体を探すのに使用されます。
http2_streams_index_sizeはこの配列の長さを指定します。
例えばhttp2_streams_index_sizeに「8」を指定した場合は図のようになります。
図のように長さ8の配列によってストリームが管理されます。ハッシュ法(チェイン法)であり、同じインデックスに属するストリームは、イデックス毎にリスト構造になります。
格納されるインデックスは、ストリームIDを元に算出されます。
index = (sid >> 1) & (http2_streams_index_size - 1)
例えば、http2_streams_index_sizeが8の場合では、ストリームID:19のインデックスは1になります。
ngx_http_v2_get_node_by_id
次に、streams_indexの使われ方を確認します。
streams_indexはngx_http_v2_get_node_by_id関数で使用されます。ngx_http_v2_get_node_by_idは指定されたストリームIDから、一致するngx_http_v2_node_sを探す関数です。(また、無かった場合に追加する場合もあります。)
このngx_http_v2_get_node_by_idはHEADERSフレームを受信した際に新しくstreams_indexに追加する際や、PRIORITYフレームにより依存ストリームをセットする際、WINDOW_UPDATEフレームによりWindowサイズが変更される際、などに呼び出されます。
そのたびに、streams_indexを用いて指定されたストリームIDを探索します。
探索のおおまかな流れはストリームIDより、格納されているstreams_indexのインデックスを参照する。無ければ、リストを順々にたどっていきます。
http2_streams_index_size
さて大体の概要が分かった所で、http2_streams_index_sizeの設定について考察します。
考慮するポイントとしては以下の二点になるかと思います
- streams_indexが短いと各インデックスのリストが長くなり、探索時に辿る処理が多くなる
- streams_indexは接続初期時に確保されるため、コネクション毎に初期確保するメモリが増える
- http2_max_concurrent_streamsを下げれば、見つかる場合はリストを辿る距離は短くなるはず。(見つからない場合はリストを最後まで辿る)
あんまり頑張ってチューニングする必要はないと思う。
個人的には探索のコストはあまり気にしなくて良いと思う...
いくつか試してみたが、1,2,4はやはり少なすぎる、128や増やしてもあまり効果は薄そう。やはり32前後が一番よさそう。
よっぽどメモリがきになるようであれば、デフォルトの32より減らすとかあるかもしれない?