← 中文资源

简体中文版本

队头阻塞

队头阻塞指共享有序通道中一个停滞项阻塞其后所有独立项的病理现象,在 HTTP 应用层与 TCP 字节流层都会出现。

阅读英文原文

概念定义

队头阻塞是排队病理:单个延迟或丢失的项阻止同一有序通道上后续独立项的交付。HTTP/1.1 中一个慢响应会阻塞整条连接;HTTP/2 over TCP 中,一个丢包会停顿所有复用流,因为 TCP 保证整条连接的字节顺序。

工作机制

它出现在两层:HTTP 层由 HTTP/2 的交错帧解决;传输层则被继承——所有流的帧共用一条有序字节流,百分之一的丢包率就可能让大量流等待重传。QUIC 把交付跟踪下沉到每个流,只阻塞真正丢数据的流,从传输层根治。

使用场景

干净的数据中心网络里影响很小;在移动与长距离有真实丢包的路径上它占主导。协议选择、连接数与流数都是调节杠杆,在复用效率与停顿波及面之间取舍。

常见误区

把 HTTP/2 与六条并行 HTTP/1.1 连接在有损网络上对比,容易把部署差异误判为协议本质。诊断需要按流的计时与重传计数器,因为症状是无关请求的弥散性延迟。评估协议应在合成丢包下测试,而不只在干净链路上跑分。

代码示例

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

.animate-fade {
  animation: fadeIn 0.3s ease-out forwards;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}
package main

import (
	"compress/gzip"
	"fmt"
	"net/http"
	"strings"
)

type gzipWriter struct {
	http.ResponseWriter
	writer *gzip.Writer
}

func (g *gzipWriter) Write(data []byte) (int, error) {
	return g.writer.Write(data)
}

func GzipMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Vary", "Accept-Encoding")
		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			next.ServeHTTP(w, r)
			return
		}
		w.Header().Set("Content-Encoding", "gzip")
		compressor := gzip.NewWriter(w)
		defer compressor.Close()
		next.ServeHTTP(&gzipWriter{ResponseWriter: w, writer: compressor}, r)
	})
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		fmt.Fprintln(w, strings.Repeat("hello gzip ", 64))
	})
	_ = http.ListenAndServe(":8080", GzipMiddleware(mux))
}