Network Programming
常用指令
Top
us,sy,ni,id,wa,hi,si,st
us: is meaning of "user CPU time"
sy: is meaning of "system CPU time"
ni: is meaning of" nice CPU time"
id: is meaning of "idle"
wa: is meaning of "iowait"
hi:is meaning of "hardware irq"
si : is meaning of "software irq"
st : is meaning of "steal time"
us 用戶空間佔用CPU百分比
sy 內核空間佔用CPU百分比
ni 用戶進程空間內改變過優先級的進程佔用CPU百分比
id 空閒CPU百分比
wa 等待輸入輸出的CPU時間百分比
hi 硬件中斷
si 軟件中斷
st: 實時
(來源http://bbs.chinaunix.net/thread-1958596-1-1.html)
software irq (si)
- MYSQL数据库网卡软中断不平衡问题及解决方案
- 分布式通讯优化篇 – IRQ affinity 窮人方案: 單隊列CPU均衡 富人方案: 網卡多隊列 bypass kernel : DPDK
nmon
https://nmon.sourceforge.net/pmwiki.php
如果 Interrupts 和 Context 特別多, 可能發送給 kafka 都是小消息, 沒有批量
nload
tcpflow
https://linux.die.net/man/1/tcpflow
dmesg -T
vim /var/log/messages
netstat -s
ss -s
vmstat
iostat
iotop
lsof -p
strace -p {pid}
perf top
free -m
ethtool -i eth0
https://www.brendangregg.com/linuxperf.html

網路通訊協議
互聯網的核心是一系列協議,總稱為”互聯網協議”(Internet Protocol Suite),正是這一些協議規定了電腦如何連接和組網。 主要協議分為: Socket
- 接口抽象層
TCP / UDP
- 面向連接(可靠) / 無連接(不可靠)
HTTP1.1 / HTTP2 / QUIC(HTTP3)
- 超文本傳輸協議

網路七層
圖片來源:網路概論 第二章、網路 OSI 模型
實體的資料在網路上傳輸,讓會議更好表現更好應用了
| OSI模型 | |
|---|---|
| 應用層(application layer)OSI Layer 7 | DHCP(v6, DNS, FTP, Gopher, HTTP(SPDY、HTTP/2) , RPC |
| 表現層(presentation layer)OSI Layer 6 | 該層被棄用。應用層的HTTP、FTP、Telnet等協定有類似的功能。傳輸層的TLS/SSL也有類似功能。 |
| 會議層(session layer)OSI Layer 5 | 該層被棄用。應用層的HTTP、RPC、SDP、RTCP等協定有類似的功能。 |
| 傳輸層(transport layer) OSI Layer 4 | TCP(T/TCP · Fast Open), UDP, DCCP, SCTP, RSVP, PPTP, TLS/SSL |
| 網路層(network layer)OSI Layer 3 | IP(v4·v6), ICMP(v6),IGMP, IS-IS, IPsec, BGP, RIP, OSPF, RARP |
| 資料連結層(data link layer)OSI Layer 2 | Wi-Fi(IEEE 802.11, ARP, WiMAX(IEEE 802.16), ATM, DTM, 權杖環, 乙太網路, FDDI, 訊框中繼, GPRS, EV-DO, HSPA, HDLC, PPP, PPPoE, L2TP, ISDN, SPB, STP |
| 實體層(physical layer)OSI Layer 1 | 乙太網, 數據機, 電力線通訊, 同步光網路, G.709, 光導纖維, 同軸電纜, 雙絞線 |
Socket 抽象層
應用程序通常通過“套接字(Socket)”向網絡發出請求或者應答網絡請求。
一種通用的面向流的網絡接口
主要操作:
- 建立、接受連接
- 讀寫、關閉、超時
- 獲取地址、端口
TCP 可靠連接,面向連接的協議
TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,是一種面向連接(連接導向)的、可靠的、基於字節流的傳輸層(Transport layer)通信協議,因為是面向連接的協議。
服務端流程:
- 監聽端口
- 接收客戶端請求建立連接
- 創建 goroutine 處理連接
客戶端流程:
- 建立與服務端的連接
- 進行數據收發
- 關閉連接

UDP 不可靠連接,允許廣播或多播
UDP 協議(User Datagram Protocol)中文名稱是用戶數據報協議,是 OSI(Open System Interconnection,開放式系統互聯)參考模型中一種無連接的傳輸層協議。
一個簡單的傳輸層協議:
- 不需要建立連接
- 不可靠的、沒有時序的通信
- 數據報是有長度(65535-20=65515)
- 支持多播和廣播
- 低延遲,實時性比較好
- 應用於用於視頻直播、遊戲同步

HTTP 超文本傳輸協議
HTTP(HyperText Transfer Protocol)是互聯網上應用最為廣泛的一種網絡協議,它詳細規定了瀏覽器和萬維網服務器之間互相通信的規則,通過因特網傳送萬維網文檔的數據傳送協議。
request message:
- Method: HEAD/GET/POST/PUT/DELETE
- Accept:text/html、application/json
- Content-Type:
- application/json
- application/x-www-form-urlencoded
- request body
response message:
- HTTP Status Code (200/400/500)
- Response Header
- response boy
GET / HTTP/1.1
Host: www.google.com
Content-Type: text/html
Connection: keep-alive
--------
HTTP/1.1 200 OK
Content-Length: 3059
Server: GWS/2.0
Content-Type: text/html
Connection: keep-alive
<html>...
nload
tcpflow
ss
netstat
nmon
top
HTTP 演進
HTTP 發展史:
- 1991 年發布初代 HTTP/0.9 版
- 1996 年發布 HTTP/1.0 版
- 1997 年是 HTTP/1.1 版,是到今天為止傳輸最廣泛的版本
- 2015 年發布了 HTTP/2.0 版,優化了 HTTP/1.1 的性能和安全性
- 2018 年發布的 HTTP/3.0 版,使用 UDP 取代 TCP 協議
HTTP2:
- 二進制分幀,按幀方式傳輸
- 多路復用,代替原來的序列和阻塞機制
- 頭部壓縮,通過 HPACK 壓縮格式
- 服務器推送,服務端可以主動推送資源
HTTP3:
- 連接建立延時低,一次往返可建立HTTPS連接
- 改進的擁塞控制,高效的重傳確認機制
- 切換網絡保持連接,從4G切換到WIFI不用重建連接

Go 網絡編程
Go 網絡編程 - 基礎概念
基礎概念:
- Socket:數據傳輸
- Encoding:內容編碼
- Session:連接會話狀態
- C/S模式:通過客戶端實現雙端通信
- B/S模式:通過瀏覽器即可完成數據的傳輸
簡單例子:
- 通過TCP/UDP實現網絡通信
網絡輪詢器:
- 多路復用模型
- 多路復用模塊
- 文件描述符
- Goroutine 喚醒
Go 網絡編程 - TCP簡單例子
package main
import (
"bufio"
"log"
"net"
)
func handleConn(conn net.Conn) {
defer conn.Close()
// 讀寫緩衝區, 減少 syscall
rd := bufio.NewReader(conn)
wr := bufio.NewWriter(conn)
for {
line, _, err := rd.ReadLine()
if err != nil {
log.Printf("read error: %v\n", err)
return
}
wr.WriteString("hello ")
wr.Write(line)
wr.Flush() // 一次性syscall
}
}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:10000")
if err != nil {
log.Fatalf("listen error: %v\n", err)
}
for {
conn, err := listen.Accept()
if err != nil {
log.Printf("accept error: %v\n", err)
continue
}
// 開始goroutine監聽連接
go handleConn(conn)
}
}
Go 網絡編程 - UDP簡單例子
package main
import (
"log"
"net"
)
func main() {
listen, err := net.ListenUDP("udp", &net.UDPAddr{Port: 20000})
if err != nil {
log.Fatalf("listen error: %v\n", err)
}
defer listen.Close()
for {
var buf [1024]byte
n, addr, err := listen.ReadFromUDP(buf[:])
if err != nil {
log.Printf("read udp error: %v\n", err)
continue
}
data := append([]byte("hello "), buf[:n]...)
listen.WriteToUDP(data, addr)
}
}
echo -n "haha" | nc -u -w1 127.0.0.1 20000
Go 網絡編程 - I/O模型
Linux下主要的IO模型分為:
- Blocking IO - 阻塞I O
- Nonblocking IO - 非阻塞IO
- IO multiplexing - IO 多路復用
- Signal-driven IO - 信號驅動式IO(異步阻塞)
- Asynchronous IO - 異步IO
同步:調用端會一直等待服務端響應,直到返回結果 異步:調用端發起調用之後不會立刻返回,不會等待服務端響應 阻塞:服務端返回結果之前,客戶端線程會被掛起,此時線程不可被 CPU 調度,線程暫停運行 非阻塞:在服務端返回前,函數不會阻塞調用端線程,而會立刻返回 
Go 語言在採用 I/O 多路復用 模型處理 I/O 操作, 但是他沒有選擇最常見的系統調用 select。 雖然 select 也可以提供 I/O 多路復用的能力,但是使用它有比較多的限制:
- 監聽能力有限 — 最多只能監聽 1024 個文件描述符;
- 內存拷貝開銷大 — 需要維護一個較大的數據結構存儲文件描述符,該結構需要拷貝到內核中;
- 時間複雜度 𝑂(𝑛) — 返回準備就緒的事件個數後,需要遍歷所有的文件描述符;
I/O多路復用:進程阻塞於 select,等待多個 IO 中的任一個變為可讀,select調 用返回,通知相應 IO 可以讀。它可以支持單線程響應多個請求這種模式。

Go 網絡編程 - 多路復用模塊
為了提高 I/O 多路復用的性能 不同的操作系統也都實現了自己的 I/O 多路復用函數,例如:epoll、kqueue 和 evport 等 Go 語言為了提高在不同操作系統上的 I/O 操作性能,使用平台特定的函數實現了多個版本的網絡輪詢模塊:
- src/runtime/netpoll_epoll.go
- src/runtime/netpoll_kqueue.go
- src/runtime/netpoll_solaris.go
- src/runtime/netpoll_windows.go
- src/runtime/netpoll_aix.go
- src/runtime/netpoll_fake.go
Goim 長連接網關
Goim 長連接 TCP 編程 - 概覽
- Comet 長連接管理層,主要是監控外網 TCP/Websocket端口,並且通過設備 ID 進行綁定 Channel 實現,以及實現了 Room 合適直播等大房間消息廣播。
- Logic 邏輯層,監控連接 Connect、Disconnect 事件,可自定義鑑權,進行記錄 Session 信息(設備 ID、ServerID、用戶 ID),業務可通過設備 ID、用戶 ID、RoomID、全局廣播進行消息推送。
- Job 通過消息隊列的進行推送消峰處理,並把消息推送到對應 Comet 節點。
各個模塊之間通過 gRPC 進行通信。

Goim 長連接 TCP 編程 - 協議設計
主要以包/針方式:
- Package Length,包長度 , int32 (4 bytes) 用 pkg.go.dev/encoding/binary, BigEndian, LittleEndian
- Header Length,頭長度
- Protocol Version,協議版本
- Operation,操作碼
- Sequence 請求序號 ID
- Body,包內容
Operation:
- Auth
- Heartbeat
- Message
Sequence
- 按請求、響應對應遞增 ID

Big-Endian
是指資料放進記憶體中的時候,最高位的位元組會放在最低的記憶體位址上

在 IP 的通訊協定中,明確規定網路上傳輸的資料都使用 Big-Endian 的方式傳輸,如果我們需要將資料透過網路傳送時,可以使用 htonl、htons、ntohl 與 ntohs 這幾個函數來處理本機與網路之間的位元組順序轉換
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
typedef union {
uint32_t l;
unsigned char c[4];
} EndianTest;
// 輸出位元組順序
void printBytes(uint32_t x) {
EndianTest et;
et.l = x;
for (int i = 0; i < 4; i++) {
printf("0x%02X ", et.c[i]);
}
printf("n");
}
int main() {
uint32_t x = 0x12345678;
printf("0x%X 在記憶體中的儲存順序:", x);
printBytes(x);
uint32_t n = htonl(x);
printf("0x%X 在網路中的傳輸順序:", x);
printBytes(n);
}
0x12345678 在記憶體中的儲存順序:0x78 0x56 0x34 0x12
0x12345678 在網路中的傳輸順序:0x12 0x34 0x56 0x78
Little-Endian
最高位的位元組放在最高的記憶體位址上。

#include <stdio.h>
typedef union {
unsigned long l;
unsigned char c[4];
} EndianTest;
int main() {
EndianTest et;
et.l = 0x12345678;
printf("本系統位元組順序為:");
if (et.c[0] == 0x78 && et.c[1] == 0x56 && et.c[2] == 0x34 && et.c[3] == 0x12) {
printf("Little Endiann");
} else if (et.c[0] == 0x12 && et.c[1] == 0x34 && et.c[2] == 0x56 && et.c[3] == 0x78) {
printf("Big Endiann");
} else {
printf("Unknown Endiann");
}
printf("0x%lX 在記憶體中的儲存順序:n", et.l);
for (int i = 0; i < 4; i++) {
printf("%p : 0x%02Xn", &et.c[i], et.c[i]);
}
return 0;
}
在 Intel CPU 的電腦中執行的結果會類似這樣:
# 本系統位元組順序為:Little Endian
# 0x12345678 在記憶體中的儲存順序:
0x7fffbffafb10 : 0x78
0x7fffbffafb11 : 0x56
0x7fffbffafb12 : 0x34
0x7fffbffafb13 : 0x12
source from : https://blog.gtwang.org/programming/difference-between-big-endian-and-little-endian-implementation-in-c/
Goim 長連接 TCP 編程 - 邊緣節點
Comet 長連接連續節點,通常部署在距離用戶比較近,通過 TCP 或者 Websocket 建立連接,並且通過應用層 Heartbeat 進行保活檢測,保證連接可用性。 節點之間通過雲 VPC 專線通信,按地區部署分佈。 國內:
- 華北(北京)
- 華中(上海、杭州)
- 華南(廣州、深圳)
- 華西(四川) 國外:
- 香港、日本、美國、歐洲

Goim 長連接 TCP 編程 - 負載均衡
長連接負載均衡比較特殊,需要按一定的負載算法進行分配節點,可以通過 HTTPDNS 方式,請求獲致到對應的節點 IP 列表,例如,返回固定數量 IP,按一定的權重或者最少連接數進行排序,客戶端通過 IP 逐個重試連接;
- Comet 註冊 IP 地址,以及節點權重,定時 Renew當前節點連接數量;
- Balancer 按地區經緯度計算,按最近地區(經緯度)提供 Comet 節點 IP 列表,以及權重計算排序;
- BFF 返回對應的長連接節點 IP,客戶端可以通過 IP直接連;
- 客戶端 按返回 IP 列表順序,逐個連接嘗試建立長連接

Goim 長連接 TCP 編程 - 心跳保活機制
長連接斷開的原因:
- 長連接所在進程被殺死
- NAT 超時
- 網絡狀態發生變化,如移動網絡 & Wifi 切換、斷開、重連
- 其他不可抗因素(網絡狀態差、DHCP 的租期等等 )
高效維持長連接方案
- 進程保活(防止進程被殺死)
- 心跳保活(阻止 NAT 超時)
- 斷線重連(斷網以後重新連接網絡)
自適應心跳時間
- 心跳可選區間,[min=60s,max=300s]
- 心跳增加步長,step=30s
- 心跳週期探測,success=current + step、fail=current - step
Goim 長連接 TCP 編程 - 用戶鑑權和 Session 信息
用戶鑑權,在長連接建立成功後,需要先進行連接鑑權,並且綁定對應的會話信息;
Connect,建立連接進行鑑權,保存 Session 信息:
- DeviceID,設備唯一 ID
- Token,用戶鑑權 Token,認證得到用戶 ID
- CometID,連接所在 comet 節點
Disconnect,斷開連接,刪除對應 Session 信息:
- DeviceID,設備唯一 ID
- CometID,連接所在 Comet 節點
- UserID,用戶 ID
Session,會話信息通過 Redis 保存連接路由信息:
- 連接維度,通過 設備 ID 找到所在 Comet 節點
- 用戶維度,通過 用戶 ID 找到對應的連接和 Comet所在節點

Goim 長連接 TCP 編程 - Comet
Comet 長連接層,實現連接管理和消息推送:
- Protocol,TCP/Websocket 協議監聽;
- Packet,長連接消息包,每個包都有固定長度;
- Channel,消息管道相當於每個連接抽象,最終TCP/Websocket 中的封裝,進行消息包的讀寫分發;
- Bucket,連接通過 DeviceID 進行管理,用於讀寫鎖拆散,並且實現房間消息推送,類似 Nginx Worker;
- Room,房間管理通過 RoomID 進行管理,通過鍊錶進行Channel 遍歷推送消息;
每個 Bucket 都有獨立的 Goroutine 和讀寫鎖優化:
Buckets {
channels map[string]*Channel
rooms map[string]*Room
}

Goim 長連接 TCP 編程 - Logic
Logic 業務邏輯層,處理連接鑑權、消息路由,用戶會話管理; 主要分為三層:
- sdk,通過 TCP/Websocket 建立長連接,進行重連、心跳保活;
- goim,主要負責連接管理,提供消息長連能力;
- backend,處理業務邏輯,對推送消息過慮,以及持久化相關等;

Goim 長連接 TCP 編程 - Job
業務通過對應的推送方式,可以對連接設備、房間、用戶 ID 進行推送,通過 Session 信息定位到所在的Comet 連接節點,並通過 Job 推送消息; 通過 Kafka 進行推送消峰,保證消息逐步推送成功; 支持的多種推送方式:
- Push(DeviceID, Message)
- Push(UserID, Message)
- Push(RoomID, Message)
- Push(Message)
Goim 長連接 TCP 編程 - 推拉結合
在長連接中,如果想把消息通知所有人,主要有兩種模式:一種是自己拿廣播通知所有人,這叫“推”模式;一種是有人主動來找你要,這叫“拉”模式。 ; 在業務系統中,通常會有三種可能的做法:
- 推模式,有新消息時服務器主動推給客戶端;
- 拉模式,由前端主動發起拉取消息的請求;
- 推拉結合模式,有新消息實時通知,客戶端再進行新的消息摘取;
Goim 長連接 TCP 編程 - 讀寫擴散
一般消息系統中,通常會比較關註消息存儲; 主要進行考慮“讀”、“寫”擴散,也就是性能問題;
在不同場景,可能選擇不同的方式:
讀擴散,在IM系統裡的讀擴散通常是每兩個相關聯的人就有一個信箱,或者每個群一個信箱。
- 優點:寫操作(發消息)很輕量,只用寫自己信箱
- 缺點:讀操作(讀消息)很重,需要讀所有人信箱
- 適合大群
寫擴散,每個人都只從自己的信箱裡讀取消息,但寫(發消息)的時候需要所有人寫一份, 所以你發消息的時候假如500人,就會寫500次
- 優點:讀操作很輕量
- 缺點:寫操作很重,尤其是對於群聊來說
- 適合群聊人數不多的情況下

Goim 長連接 TCP 編程 - 唯一 ID 設計
唯一 ID,需要保證全局唯一,絕對不會出現重複的 ID,且 ID 整體趨勢遞增。 通常情況下,ID 的設計主要有以下幾大類:
- UUID
- 基於 Snowflake 的 ID 生成方式
- 基於申請 DB 步長的生成方式
- 基於 Redis 或者 DB 的自增 ID生成方式
- 特殊的規則生成唯一 ID

Snowflake
Snowflake,is a network service for generating unique ID numbers at high scale with some simple guarantees. id is composed of:
- time - 41 bits (millisecond precision w/ a custom epoch gives us 69 years)
- configured machine id - 10 bits - gives us up to 1024 machines
- sequence number - 12 bits - rolls over every 4096 per machine (with protection to avoid rollover in the same ms)

Sonyflake
Sonyflake,is a distributed unique ID generator inspired by Twitter's Snowflake. id is composed of:
- 39 bits for time in units of 10 msec
- 8 bits for a sequence number
- 16 bits for a machine id
As a result, Sonyflake has the following advantages and disadvantages:
- The lifetime (174 years) is longer than that of Snowflake (69 years)
- It can work in more distributed machines (2^16) than Snowflake (2^10)
- It can generate 2^8 IDs per 10 msec at most in a single machine/thread (slower than Snowflake)

基於步長遞增的分佈式 ID 生成器
基於步長遞增的分佈式 ID 生成器,可以生成基於遞增,並且比較小的唯一 ID; 服務主要分為:
- 通過 gRPC 通信,提供 ID 生成接口,並且攜帶業務標記,為不同業務分配 ID;
- 部署多個 id-server 服務,通過數據庫進行申請 ID步長,並且持久化最大的 ID,例如,每次批量取1000到內存中,可減少對 DB 的壓力;
- 數據庫記錄分配的業務 MAX_ID 和對應 Step ,供Sequence 請求獲取;

IM(即時通訊, Instant Messaging) 私信系統
在聊天系統中,我們幾乎每個人都在使用聊天應用,並且對消息及時性要求也非常高; 對消息也需要有一致性保證; 並且都有著豐富的多媒體傳輸功能:
- 1 on 1
- Group chat
- Online presence
- Multiple device support
- Push notifications
在聊天系統中,主要是客戶端和服務端之間進行通信; 客戶端可以是 Android、iOS、Web 應用; 通常客戶端之間不會進行直接通信,而是客戶端連接到服務端進行通信; 服務端需要支持:
- 接收各個客戶端消息
- 消息轉發到對應的人
- 用戶不在線,存儲新消息
- 用戶上線,同步所有新消息

在聊天系統中,最重要的是通信協議,如何有保證地及時送達消息; 一般來看,移動端基本都是通過長連方式實現,而 Web 端可以使用 HTTP、Websocket 實現實時通信; 常用通信方式:
- HTTP 定時輪詢
- HTTP 長輪詢
- WebSocket
- TCP

在聊天系統中,有著很多用戶、消息功能,比如: 登錄、註冊、用戶信息,可以通過 HTTP API 方式; 消息、群聊、用戶狀態,可以通過 實時通信 方式; 可能集群一些三方的服務,比如 小米、華為推送、APNs 等; 所以,主要服務可為三大類:
- 無狀態服務
- 有狀態服務
- 第三方集成

在聊天系統中,Goim 主要角色是 Real time service,實現對 連接 和 狀態 的管理:
可以通過 API servers 進行系統之間的解耦;
各個服務的主要功能為:
- 聊天服務進行消息的 發送和接收
- 在線狀態服務管理用戶 在線和離線
- API 服務處理 用戶登錄、註冊、修改信息
- 通知服務器發送推送通知(Notification)
- 通過 KV 存儲進行 存儲、查詢 聊天信息

在聊天系統中,消息存儲是最主要的,通常會有海量的消息需要存儲,我們也會想到 關係數據庫還是NoSQL 數據庫; 而關係數據庫主要進行存儲用戶信息,好友列表,群組信息,通過主從、分片基本滿足; 由於消息存儲比較單一,可以通過 KV 存儲; KV 存儲消息的好處:
- 水平擴展
- 延遲低
- 訪問成本低

一對一聊天,主要的消息發送流程:
- 用戶 A 向聊天服務發送消息給用戶 B
- 聊天服務從生成器獲取消息 ID
- 聊天服務將消息發到消息隊列
- 消費保存在 KV 存儲中
- 如果用戶在線,則轉發消息給用戶
- 如果用戶不在線,則轉發到通知服務(Notification)

群聊
群聊,較為複雜,通常有多寫、多讀兩種方式;
單信箱(多寫, 寫擴散? ),每個用戶都保存一份消息:
- 消息同步流程比較簡單,每個客戶端僅需要讀取自己的信箱,即可獲取新消息
- 當群組比較小時,成本也不是很高,例如微信群通常為 500 用戶上限
- 對數組數量無上限
多信箱(多讀, 讀擴散? ),每個群僅保存一份消息:
- 用戶需要同時查詢多個信箱
- 如果信箱比較多,查詢成本比較高
- 需要控制群組上限
寫擴散,每個人都只從自己的信箱裡讀取消息,但寫(發消息)的時候需要所有人寫一份, 所以你發消息的時候假如500人,就會寫500次
- 優點:讀操作很輕量
- 缺點:寫操作很重,尤其是對於群聊來說
- 適合群聊人數不多的情況下
讀擴散,在IM系統裡的讀擴散通常是每兩個相關聯的人就有一個信箱,或者每個群一個信箱。
- 優點:寫操作(發消息)很輕量,只用寫自己信箱
- 缺點:讀操作(讀消息)很重,需要讀所有人信箱
- 適合大群

Reference
- Go 语言设计与实现 - 6.6 网络轮询器
- 李文周的博客 - Go语言基础之网络编程
- HTTP 的特性
- Android微信智能心跳方案
- https://juejin.cn/post/6844903827536117774
- 如何设计一个亿级消息量的 IM 系统
- Leaf:美团分布式ID生成服务开源
- 系统调优,你所不知道的TIME_WAIT和CLOSE_WAIT
- Java核心(五)深入理解BIO、NIO、AIO
- https://www.infoq.cn/article/the-road-of-the-growth-weixin-backgroundhttps://systeminterview.com/design-a-chat-system.php
壓測遇到問題
壓測時,當六萬多的連接後, 就連不是上了.
因為 tcp連接的五元組(5-tuple)連接埠有限制, 他是一個int16 (65535)
5元組是一個通信術語,英文名稱為five-tuple,或5-tuple,通常指由源Ip (source IP), 源端口(source port),目標Ip (destination IP), 目標端口(destination port),4層通信協議 (the layer 4 protocol)等5個字段來表示一個會話
可用指令新增虛擬網卡 就可以建立更多連接.
# https://guideah.com/2021/06/67201/
# 命令就可以在eth0網卡上創建一個叫eth0:0的虛擬網卡,他的地址是:192.168.1.63
sudo ifconfig eth0:0 192.168.10.10 up
# 如果不想要這個虛擬網卡瞭,可以使用如下命令刪除:
sudo ifconfig eth0:0 down
