WADA-DEV(7) $ /ja/blog/reverse-meat-proxy/

NAME

reverse-meat-proxy — meat proxy の逆はなんと呼ぶべきか

SYNOPSIS

Hacker News で見かけた meat proxy(AI の生出力をそのまま貼るだけの人間)を起点に、その鏡像である reverse meat proxy を考えた。判定軸は「何かを足しているか」ではなく「終端しているか」に置くのが正しかった、という話と、語呂は良いのに構造が対応せず没にした候補たち。

DESCRIPTION

はじめに

Hacker News で meat proxy という語を見かけた。AI の生出力をそのまま貼るだけで、自分では何も足さない人間のことだ。上流が AI で、下流が人間。肉でできた proxy、というわけだ。

うまい言い方だと思ったが、同時に「逆向きのほうもあるな」と思った。外からの要求を受けて、中の人間に振るだけ。上流も下流も人間。つまり reverse meat proxy だ。

思いついた語を並べておくだけの記事にするつもりだったが、並べようとしたら手が止まった。この手の比喩は、判定軸を決めないと何でも作れてしまって、作った端から破綻する。なので判定軸を決める話と、それで没にした候補の話になった。

判定軸は「足しているか」ではなく「終端しているか」

最初、この手の中継の悪さは「付加価値ゼロ」にあると思っていた。でもそれだと reverse proxy の比喩として成立しない。

reverse proxy の本質は、宛先の選定でもコンテンツの付加でもないからだ。バックエンドが 1 台しかない reverse proxy は普通に存在するし、それでも十分に役に立っている。ならば何が本質かというと、クライアント接続をそこで終端し、バックエンドの窓口として自分が名乗ることだ。

そしてこの「終端する」という性質には、避けがたい帰結がついてくる。バックエンドが落ちたとき、クライアントから見た障害の窓口が自分になるという点だ。典型的には自分の名前で 5xx を返すことになる。壊れているのが自分でなくても、障害箇所として名乗るのは自分になる。

もっとも、必ず 5xx を返すわけではない。stale-if-error で古い応答を返すこともできるし、別の上流にフェイルオーバして失敗をそもそも見せないこともできる。ただしこれは反例ではなく、むしろ話を補強する。隠すことを選べるのは、帰属を握っているからだ。 終端するとは、失敗の帰属を引き受けることとほぼ同義になる。

そう考えると、素通しの中継の何が問題なのかがはっきりする。足していないことではない。indirection の利得 — 外から見て窓口が 1 つに見えること — だけを取って、終端の責務を引き受けていないことだ。

終端しているかで、同じ機構が反転する

この軸で並べると、良い比喩と悪い比喩が分かれる。分類したいのは人ではなく振る舞いなので、1 つの機構につき両側を置く。

機構終端している(価値が出る)終端していない(病理)
proxy自分が出したものとして名乗るので、出す前に検証する生出力をそのまま貼り、間違いは元の出力のせいにする(meat proxy
reverse proxyバックエンドの失敗を自分の名前で返す窓口の利得だけ取り、責任は受け手に残す(reverse meat proxy
cache「これは自分の手元の古い答えだ」と自分で言う鮮度を誰も検証しないまま、古い答えを自信満々で返す
queuebackpressure をかけて自分の判断で断る受領の ACK を完了の合図として使わせ、滞留を隠す

queue の行が地味に効く。厄介なのは、ここで返る ACK 自体は嘘ではないところだ。ブローカーの enqueue ACK が意味するのは「受理して永続化した」であって「処理した」ではない。どこにも嘘がないまま、受領した時点で依頼者は着手されたと思い込み、そのぶん待ち続けることになる。断ってくれれば別の手を打てた。断らない中継のほうが、断る中継より始末が悪いことがある。

cache の病理も、鮮度切れだけではない。より検知しづらいのはキーが粗いほうだ。本来キーに含めるべき入力が入っていないせいで、別の問いへの答えが、いまの問いへの答えとして返る。HTTP でいえば Vary に必要なヘッダを入れ忘れている状態で、web cache poisoning の主要因でもある。答えそのものは正しく、鮮度も落ちていない。だから返した側にも受け取った側にも矛盾が見えない。終端していればここで「その問いには答えていない」と言えるが、終端していない中継は手元にあった応答をそのまま 200 で返してしまう。

採用しなかった候補

語呂は良いのに、機構の性質と振る舞いが構造的に対応しなかったもの。没にした理由のほうが、上の判定軸が実際に効いている例になっている。

meat NAT。 「中で誰がやったか外から見えない」を病理として使いたかったが、これは NAT が正しく動いているときの挙動であって、劣化例にならない。しかも NAT は、フローが生きているあいだは変換テーブルで対応関係を保持している。言いたかったのは NAT ではなく、相関 ID / Via / X-Forwarded-For の伝播が切れることのほうだった。そちらなら構造が一致する。

meat 502。 502 が意味するのは「上流に問い合わせた結果、不正な応答が返った」だ。時間内に応答が得られなければ 504。上流に繋がらなかったときにどれを返すかは RFC が決めておらず、nginx は 502、haproxy や Envoy は 503 と実装ごとに割れている。そして「そもそも問い合わせずに自分で答えを合成した」に対応する 5xx は存在しない(2xx でよければ 203 Non-Authoritative Information があるが、成功として返るので失敗の帰属の話には使えない)。使いたかった「gateway が自分を障害箇所として名乗る」という性質自体は、上の表の reverse proxy 行に吸収できた。

meat firewall / meat switch。 一般的すぎて、何の性質も特定していない。ただ機械の名前を人間に貼っただけになる。

おわりに

判定軸を「終端しているか」に置いたことで、造語の当たり外れが自分でも判定できるようになった。上の 4 つが残り、3 つが落ちた。落ちた 3 つはどれも語呂が良かったので、軸が無ければたぶん採用していた。

ひとつ注意しておくと、reverse meat proxy は人の属性ではない。そのときの振る舞いの形でしかなくて、同じ人が場面によって終端したりしなかったりする。人に貼ると、ただの悪口として機能してしまう。自分の直近の中継を思い出して、要求を投げる側の path に何を足したか数えるほうの使い方をしたい。

SEE ALSO

COMMENTS