Go 1.27 で HTTP/1 接続の再利用が向上

2026/10/15 1:29

Go 1.27 で HTTP/1 接続の再利用が向上

RSS: https://news.ycombinator.com/rss

要約▶

Japanese Translation:

Go 1.27 は、HTTP/1 プロトコルにおいて未読み取りレスポンスボディを自動的に処理することで、接続を安全に閉じるために以前必要だった手動の労力を実質的に排除し、重要な進歩を示しています。このアップデートは、接続再利用に伴うレイテンシペナルティを劇的に削減し、データ損失や複雑なワークアラウンドへの心配なく、標準パターン

defer resp.Body.Close()
を安心して使用することを可能にします。以前、アプリケーションは後続のバイトが未処理の場合、高価な TCP/TLS ハンドシェイクをあえて破棄することがあり、その結果、次のリクエストに対して高コストな新しい接続が必要とされていました。新しい自動非同期ドレイン機能は、50ms または 256KB 以内に残留データを効率的に処理し、接続の放棄を防ぎつつ、明示的に閉じることを指定されたレスポンスについては作業を賢くスキップします。この変更により、開発者が未使用の大規模ファイルに帯域幅を浪費したり、意図せずにゴルーチンリークを引き起こすような歴史的問題が解決されました。これらの複雑性を内部化することで、Go の標準ライブラリはより安全なコードと効率的なクライアント管理を可能にします。究極的には、新しい接続確立の主要コストが低下することにより、業界全体のパフォーマンスが向上し、小規模かつ頻繁なリクエストが全体的に大幅に高速化され、リソース利用も少なくて済みます。

本文

Go 1.27 で実現された HTTP パフォーマンス劇的改善とその背景

概要

Go 1.26 と Go 1.27 を比較したベンチマークでは、HTTP ステータスコード取得のパフォーマンスに劇的な変化が見られました。

  • Go 1.26:
    index.golang.org
    への 100 回呼び出しで約 710 ミリ秒
  • Go 1.27: 同条件下で約 150 ミリ秒(ほぼ 5 倍の高速化)

この性能差の原因は、HTTP/1 で未読のレスポンス本体を処理する際の「接続再利用失敗」メカニズムと、Go 1.27 の自動最適化にあります。


HTTP 接続確立のコスト

新しい TCP 接続を作成するには、以下のラウンドトリップ(RTT)が発生します。

  • TCP ハンドルシャーク (1 RTT)
    • クライアント → サーバー:SYN パケット
    • サーバー → クライアント:SYN-ACK
    • クライアント → サーバー:ACK + TLS メッセージ初回
  • TLS ハンドルシャーク (2 RTT)
    • 暗号化鍵の交換とサーバー認証(TLS 1.2 の場合は 2 RTT)
  • HTTP リクエスト
    • キー交換完了後のリクエスト送信

合計:約 3 RTT

クロスリージョン通信では片方向遅延が 50ms(RTT 100ms)に達することがあり、接続確立コスト(約 300ms)は HTTP リクエスト自体の帯域幅利用効率を大幅に下回ります。

注:

index.golang.org
は TLS 1.3 をサポートしており、実際の RTT は少ないものの、コスト自体がゼロにはなりません。


接続の再利用とバージョン별 차이

HTTP クライアントは既存接続の再利用を試みますが、実装方式は HTTP バージョンによって異なります。

HTTP バージョン特徴
HTTP/1.0
Connection: keep-alive
ヘッダーが必要(公式仕様の一部ではないが一般的)。省略または
close
を送れば終了。
HTTP/1.1デフォルトで接続永続化。明示的に
Connection: close
でない限り再利用可能。
HTTP/2単一 TCP 接続内でマルチプレキシング(並列処理)が可能。

接続の再利用が失敗するメカニズム

HTTP/1 では、同じ TCP 接続上で複数のリクエストを行う際、レスポンスは バイトストリーム として連続して届きます。

net/http.Get
の動作フロー

  1. ステータス行とヘッダーを読み取り解析し、
    Response
    オブジェクトを返す。
  2. レスポンス本体(ボディ)はまだストリーム上で未読のまま。
  3. 次のレスポンスを開始するには、現在のレスポンス本体の最後まで読み取らなければならない。
    • 理由:
      Content-Length
      または
      Transfer-Encoding
      を待つ必要があるため。

問題の発生

func getStatus(url string) (int, error) {
    resp, err := http.Get(url)
    if err != nil { return 0, err }
    defer resp.Body.Close() // ここがキモ
    return resp.StatusCode, nil
}
  • Go 1.26 までの動作:
    • resp.Body.Close()
      を呼び出すと、未読のレスポンス本体があることを検知。
    • 「接続再利用失敗」:既存接続を破棄し、新規 TCP 接続を作成して次へ進む。
    • 結果: 毎回新しい接続確立コスト(RTT)が発生し続ける。

Go 1.27 の対応: これらの未読処理を内部で自動的に最適化し、接続再利用を維持します。


再利用失敗が影響しやすいパターン

「ステータスコードのみ取得」するコードでも、以下の理由で接続再利用に失敗しやすかったのです。

1. API レスポンスの詳細なボディ

  • エンドポイントが
    { "success": true, ... }
    のような詳細情報を送信する場合。
  • ステータスコードだけを抜き取り、本体を閉じるだけで接続切断されるリスクがある。

2. デコーダーの不完全な読み取り

  • encoding/json.Decoder
    が
    }
    で停止する場合でも、その後の改行などが未読で残ることがある。
  • その未読バイトを消費しないと、次のレスポンスの開始位置が見つからないため接続が切断される。

結論: 「一見無害なコード」でも、HTTP/1 では沈黙したパフォーマンス劣化を引き起こす要因でした。


手動による解決策(推奨されない)

未読ボディの問題に対処するため、開発者が独自に実装した回避策の例です。

バリエーション 1: 全排出(非推奨)

func drainAndCloseBody(body io.ReadCloser) {
    io.Copy(io.Discard, body) // 全ダウンロードして破棄
    body.Close()
}
  • 欠点: レスポンス本体が巨大な場合、新規接続コストよりもダウンロード時間が長くなる可能性。

バリエーション 2: サイズ制限付き排出

func drainAndCloseBody(body io.ReadCloser) {
    io.CopyN(io.Discard, body, 256<<10) // 最大 256 KB
    body.Close()
}

バリエーション 3: タイムアウト付き排出

func drainAndCloseBody(body io.ReadCloser) {
    drainDone := make(chan struct{}, 1)
    go func() {
        io.CopyN(io.Discard, body, 256<<10)
        drainDone <- struct{}{}
    }()
    
    select {
    case <-drainDone:
        // 完了
    case <-time.After(50 * time.Millisecond):
        // タイムアウト処理
    }
    body.Close()
}

バリエーション 4: 非同期排出(最良の試み)

複数のゴルーチンを使って、排出処理を背景で実行し、接続再利用と競争させる手法です。

欠点:

  • 実装が複雑(cumbersome)。
  • 「レスポンスボディを排出する」という慣行自体が誤解を生み(例:HTTP/2 に対して不要な排出を試みる)、マイクロバグの原因となることが多かった。

結論:Go 1.27 以降のベストプラクティス

Go 1.27 以降、

net/http.Transport
は以下の挙動を自動的に実行します。

  1. 自動的な非同期排出: 未読の HTTP/1 レスポンス本体に対して、最大 50 ミリ秒 または 256 KB の範囲まで自動排出。
  2. ヘッダー判定による最適化:
    Connection: close
    ヘッダーがある場合、無駄な排出処理をスキップ。
  3. 追加の内部最適化: 将来的なバージョンでさらなる強化が施される可能性があります。

おすすめコードパターン

複雑な回避策を入れる必要はありません。シンプルさこそが Go の哲学です。

func getStatus(url string) (int, error) {
    resp, err := http.Get(url)
    if err != nil {
        return 0, err
    }
    defer resp.Body.Close() // これだけで十分です。
    return resp.StatusCode, nil
}

要するに: コードを清潔でシンプルに保ち、複雑な最適化は

net/http
に任せましょう。

同じ日のほかのニュース

一覧に戻る →

2026/10/15 4:26

がん患者さんが知っておくべきこと:2026年版

## 日本語訳: 口がん(例:扁平上皮癌)と診断された人にとって最も重要な点は、疾病の深刻さが初期段階での対話(AI ツールを含む)で相対化されうる可能性があるため、適切なタイミングで高品質な医療を受けるよう執拗に努力し続けることです。個人的な経験から、術後採取した腫瘍組織で行われた検査よりも、生検組織を用いた検査を優先しないことが危険な遅れを引き起こす可能性があることが示されており、したがって患者は可能な限り総合的な遺伝子検査と上級がんセンターでの第二の意見を迅速に求めるべきです。メジャーな医療機関(例:MD Anderson)は、医師と病理科医間の強い協力関係によりより迅速かつ正確な回答を提供することが多く、US News ランキングを指針としてローカルコミュニティ病院よりも 2〜3 時間のドライブ圏内であっても訪問する価値があります。実用的な戦略には以下が含まれます: - ノートとフォローアップのための整理されたシステムを作成すること(例:予約要約や質問用の専用フォルダー)。 - NCCN ガイダンスの「標準治療」フローチャートを使用して、期待されるプロトコルを理解し、効果的にアドボケーシィを行うこと。 - 標準的な経路が停滞した際に特に Sijbrandij Foundation のようなリソースを求助すること。 外科医を選ぶ際には、年間手術件数や合併症発生率について問いかけ、同様の処置を受けた他の患者と話すことを検討すべきです。必要であれば有給休暇やホテルを使用してトップクラスのカンターにアクセスすることもできます;多くの施設は保険を受け入れています。結局のところ、これらの能動的なステップはキャンセルや保険手続きによる遅延を防ぎ、適切な標準治療を受けることを確実にします。

2026/10/15 5:48

OpenCode 2.0

## Japanese Translation: OpenCode 2.0 は、数百万人の毎日ユーザーからのフィードバックに基づいた大きなアーキテクチャ見直しであり、パフォーマンス向上、バグ修正、およびほぼあらゆるエージェント機能をサポートするように設計された全く新しい API を導入しています。主要な変更点として、すべてのインターフェース(TUI、Web、デスクトップ)を単一の中央バックグラウンドプロセス (`opencodepid`) に統合し、`@opencode/client` を使用するクライアントはこれを自動で発見できるようになりました。システムは現在、ペアリングフロー (`/pair` または `opencode pair`) を通じてスケジューリングされたタスクや外部アプリケーションとのシームレスな接続をサポートしており、ネイティブアプリの開発が進行中です。 目立つ機能の一つには、「Code Mode」(`@opencode/codemode`)があり、Node.js VM の複雑性なしにエージェントが直接スクリプトを書くことを可能にする最小限の JavaScript インタプリターを使用します。これにより、すべての MCP サーバーはデフォルトで code mode で動作します。この更新では、長時間実行されるタスクのためにバックグラウンドサブエージェントと非同期シェルコマンドを導入し、セッション中にプラグインのアップデートを行うためのホットリロードも追加されています。新しい `@opencode/sdk` を使用することで、OpenCode をサーバーまたは Durable Objects 上のライブラリとして利用できるようになります。 このアップグレードには重要なbreaking changesが含まれています:バージョン 1.x のプラグインはもはや機能せず、`tui.json` などの設定ファイルは `json` フォーマットに移動しました。最新の 1.x リリースを使用するユーザーは、2.0 に更新してこれらの変更との互換性を維持するには、最初に `opencode upgrade --major` を実行する必要があります。

2026/10/15 6:11

Jev 1.14.0 をリリースし、ドリーマー向けの試み機能を同時に提供します

## Japanese Translation: jev 1.14.0(`jev-preview` チャンネルで利用可能)は、「危険区域」API ヘッダーをゲート化した実験機能を提供します。これには、composable images(`TypeSafe-Danger-Zone-Images: true` を有効化により提供され、ただし以前の 1.13.0 ビルドに比べて多モーダル入力におけるパフォーマンス低下が報告されています)、エラーなしのバウディングボックスを返す新しい「box」検出タイプが含まれます。ユーザーはさらに、より長いコンテキスト長(`TypeSafe-Danger-Zone-Long-Context: true`)およびデバッグ用の Jaggedness レポートへの参加を選択でき、これらは特定のヘッダーを通じて利用可能です。このアップデートは 1.13.0 に基づいており、以前のパフォーマンス低下を解決すると同時に多言語サポートを拡張しています。評価については、内部インテリジェンス指標は非一貫的な推測として扱い、公式ベンチマークはデータポリシーの懸念から開示ウェイトモデルのみを対象としており、ランキングが特定のアーキテクチャにバイアスがかかっている可能性があるため、個人の実験に頼るべきです。今後、`jev-latest` 別名は 1 週間以内に 1.14.0 を採用します。企業は廃止スケジュールを監視する必要があります:バージョン 1.13.0 に対する 60 日間の警告期間に続いて、新しいリリース用の 30 日間のウィンドウを確保し、古いバージョンが廃棄される前にシステムがこれらの構造的変化に適応できるようにします。ドキュメントは docs.typesafe.ai/go/images、docs.typesafe.ai/go/box、および docs.typesafe.ai/models#context-length で利用可能です。

Go 1.27 で HTTP/1 接続の再利用が向上 | そっか~ニュース