# 網路伺服器效能優化


## 正文

Port 由 16 bit 表示，[埠號0是被保留的，不可使用。1--1023 系統保留，只能由root使用者使用。1024--4999 由用戶端程式自由分配。5000--65535 由伺服器端程式自由分配。在UDP協定中，來源埠號可選擇是否填上，如果設為0，則代表無來源埠號](https://zh.wikipedia.org/wiki/%E9%80%9A%E8%A8%8A%E5%9F%A0)。

在 OS 上面，可以用一個行程綁定一個 Port，負責專門處理那個 Port 的東西。

所以通常我們會用一個 Worker Process 在那個 Port 收東西，每收到一個連線，會

1. 產生一個 FD 來代表此連線
2. 然後產生一個 Process 來處理此 FD 連線

針對第一點，通常預設作業系統一個 Process 只能開啟最多 1024 Sockets，所以一些高效能伺服器會讓你設定系統超過 1024 以上的數字，像是 Nginx 允許你在設定檔中寫 `worker_rlimit_nofile 65535`。

第二點則是使用多路負用，像是 epoll，參考後面章節。

## Worker Process

如同上面講的，現在有一個 Worker Process 專門可以處理流量，用 epoll 等技術，但這樣才一個 Worker Process 只能在一個 Core 上面跑。

在現代 Linux（3.9 版本以後）中，Nginx 可以使用核心提供的 SO_REUSEPORT 功能。

1. 核心負載平衡：Linux 核心會在網路層級直接做「分流」
2. 效率極高：當一個 SYN 封包（新連線）進來時，核心會根據雜湊（Hash）演算法，直接決定要把這個連線丟給哪一個 Worker
3. 互不干擾：Worker 之間不再需要搶鎖（Lock），每個 Worker 專心處理分配給自己的連線

為了效能的極致，我們甚至會禁止 Worker 在不同核心之間「跳來跳去」（減少快取失效），在 nginx 設定檔設定 `worker_cpu_affinity auto;` 這會強迫 Worker 1 永遠住在 Core 1，Worker 2 永遠住在 Core 2。

## 多路復用

[多路復用基礎了解 and epoll vs kqueue](https://medium.com/@cozy-kola/%E5%A4%9A%E8%B7%AF%E5%BE%A9%E7%94%A8%E5%9F%BA%E7%A4%8E%E4%BA%86%E8%A7%A3-and-epoll-vs-kqueue-e79da789af0f)

## C10M

上面講的比較像是以前 C10K C100K 可以用到的技術，但針對 C1000K, C10M 考慮的就可能不是軟體優化，可能要考慮硬體幫忙，或者是繞過 Kenrel 來直接處理封包，像是 DPDK/XDP，參考以下文章：

* [Linux 网络性能优化-C10K、C1000K、C10M 问题总结](https://zhuanlan.zhihu.com/p/537843366)
* [High Concurrency 問題](https://hackmd.io/@Burgess/r1XG1kNT_)
* [分享我在第十届GOPS的PPT《百万并发下Nginx的优化之道》](https://www.taohui.pub/2018/09/19/nginx/%E5%88%86%E4%BA%AB%E6%88%91%E5%9C%A8%E7%AC%AC%E5%8D%81%E5%B1%8Agops%E7%9A%84ppt%E3%80%8A%E7%99%BE%E4%B8%87%E5%B9%B6%E5%8F%91%E4%B8%8Bnginx%E7%9A%84%E4%BC%98%E5%8C%96%E4%B9%8B%E9%81%93%E3%80%8B/)

《The C10M Problem》 (Robert Graham, 2013)：它指出 Linux Kernel 處理封包的路徑太長，導致 Nginx 無法突破千萬級連線。

Cloudflare 也自己提出代替品 Pingora，[How we built Pingora, the proxy that connects Cloudflare to the Internet](https://blog.cloudflare.com/how-we-built-pingora-the-proxy-that-connects-cloudflare-to-the-internet/)，因為他說 Nginx 有發呆的問題，並且兩個 Process 之間不共用連線池。

## Reference

* [I/O 模型演化: 事件驅動伺服器：原理和實例](https://hackmd.io/@sysprog/linux-io-model/https%3A%2F%2Fhackmd.io%2F%40sysprog%2Fevent-driven-server)
* [Inside NGINX: How We Designed for Performance & Scale](https://blog.nginx.org/blog/inside-nginx-how-we-designed-for-performance-scale)

