寫出高性能的服務與應用 那些你沒想過的事
TRANSCRIPT
“How well is the computer doing the work it is supposed to do?”
- Arnold Allen
https://en.wikipedia.org/wiki/Computer_performance
工作
• 實際上要做的事情
• 例如
- 聊天系統:大量點對點傳送訊息、群組訊息
- 售票系統:空位查詢、畫位、推不倒
- 資料庫:CRUD、Query
- Web Server:提供網頁、Web API、…
- 儲存:讀寫檔案
性能指標
• 人訂出來的期望目標
- 可同時處理 100k 人連線
- 回應時間要在 3 秒內
- 處理延遲要在 10 毫秒以下
• 系統跑出來的實際數據
- 性能測試,有數據才敢大聲說
- 結果包含硬體和軟體效能
常見性能指標
• 速度與數量
- RPS (Requests Per Second)
- QPS/TPS (Query/Transactions Per Second)
- Latency/Response Time (MS)
- b/s (Bits Per Second)
- IOPS (Input/output Operations Per Second)
• 其他:HA, Scalability, etc.
例如
• 效能指標比較好- Nginx vs Apache
- MySQL vs. PostgreSQL
- Node.js vs. Ruby, PHP 5 vs. PHP 7
• 超過服務需求
• CP 值很高- Scale down
怎麼賺錢多開機器
負載平衡
資料庫讀寫分離
資料庫分表分片
Compiler Optimization
WAL
Algorithm
B-tree
Buffer/Cache
Loop-unrolling
Multi-thread
Cloud
EXPLAIN QUERY PLAN
Scheduling
Context-switchJIT
Interrupt
Lock Contention
NO-SQL
Sync/async
C10K
Data structure
性能Mutex/Futex
Message Queue
Index
TCP/UDPSerialization
Event Loop
Affinity
Swap/paging
Memory barrier
GC
malloc
coroutine
冰山一角
http://www.bizhi360.com/fengjing/4498.html
hardware
OS
Language VM
Framework
Application / Service
Lib
了解你的系統
• 了解每一層的優點與雞肋
- 彈性 vs 性能 / 可以不要 GC 嗎?
• 符合底層的運作方法
- 硬體、OS、框架作者的抽象想法
• 使用底層提供的高性能介面
- 例如 Linux 的 sendfile(), copy_file_range()
了解硬體運作
• 硬體是最後執行地方- CPU, Memory, Disk, NIC, etc.
• 無法突破的物理限制- 計算、記憶體、儲存、網路頻寬
• 最後的抽象地點- 相同的工作方式或許最佳性能?
- 神祕的特殊功能
The Free Lunch Is Over
• 程式不會再隨著硬體升級而變快
• 程式開發時就要考慮充分利用硬體- 多核心 CPU
- 先進指令集
• 平行計算是未來http://www.gotw.ca/publications/concurrency-ddj.htm
http://www.thepenipeople.com/home/2015/12/13/physical-architecture
• CPU• Multi-core• ALU、FPU• MMU
• GPU • Disk 控制器• RAID 控制器• NIC 控制器• DMA engine• ….
其實硬體早就在平行
讓硬體同時動起來
• 重疊硬體的運作時間
- Multi-core 同時計算
- 記得 CPU 和 Disk、NIC 可以同時運作嗎?
http://minnie.tuhs.org/CompArch/Lectures/week10.html
Memory Hierarchy
• 硬體提供快的輕薄的假象
• 用在
- CPU Pre-fetch
- Read ahead
- Write buffer
- …
Regs
L1 cache
L2 cache
Main memory
Disks
Remote Disks
快、小、貴
慢、大、便宜
善用現有的硬體架構
• 讓資料待在的最快的地方
- 無所不在的 Cache 和 Buffer
- 加速讀取和寫入
• 雖然有時會採雷
- Cache coherence
- False sharing
- Power lost for Disk buffer
作業系統是你的朋友
• 幫忙完成了很多事情
- 抽像硬體
- 調度程序(多工)
- 記憶體管理
- 檔案子系統
- 網路子系統hardware
OS
Language VM
Framework
Application
Lib
作業系統是你的敵人!?
• 應用程式碰不到硬體
• 應用程式無法獨佔資源
• 通用架構(可能)造成效能不彰
• 多一層就有效能損失 (°ཀ°)
- User space vs. Kernel space
- Context switch
- Data Copy
不要閒置資源
• 重疊計算和 I/O 操作
• 選擇適合的 I/O 模型- 網路傳輸、讀寫儲存裝置、IPC
• 種類- 同步阻塞 (Blocking I/O)
- 同步非阻塞 (Non-Blocking I/O)
- 多路復用 (I/O Multiplexing)
- 異步 (Asynchronous I/O)
Blocking I/O
• 當讀寫成功後才返回
• 同時只能做一件事
- 可惜了 CPU 時間
• 簡單好用,但別再用!
http://www.ibm.com/developerworks/library/l-async/
Non-Blocking I/O
• 讀寫若發生阻塞立即返回錯誤,由應用程式負責輪詢系統
• 同時可以做多件事- 問沒有的時候就可以先處理別的事情
• 可能會 Busy looping- 有點煩,通常不單獨用
http://www.ibm.com/developerworks/library/l-async/
I/O Multiplexing
• 應用程式等作業系統通知可以讀寫
• 常見方式- select
- Linux: epoll
- BSD: kqueue
- Solaris: /dev/poll
- Windows: IOCP
• 閒著沒事就 Block, 有事可以馬上處理
http://www.ibm.com/developerworks/library/l-async/
Asynchronous I/O
• 作業系統幫你讀/寫好,再通知完成了
• 常見方式
- Linux: AIO
- Win: overlapped I/O
- I/O Thread Pool
• 問題
- 不跨平台
http://www.ibm.com/developerworks/library/l-async/
不要浪費資源
• 硬體資源有限- 通常是記憶體不夠用。如果一個 Thread 8MB stack…
• CPU 核心數限制了真實平行數- 超過其實只能排隊、Context-switch 可能會暴增
• 選擇適合的 Process 架構- Single Thread/Process
- Multiple Process
- Multiple Thread, Thread Pool
- Event-Driven
Multiple Thread
• 在單一 Process 內執行多個 Thread
• 優點- 較 Process 省記憶體
- 較 Process 啟動快
- 較 Process Context-switch 代價低
- 存取共用資料簡單
• 缺點- 複雜度高、Dead Lock、Race condition
︴︴︴︴
Thread Pool
• 限制 thread 在固定數量
• 優點- 記憶體消耗小
- 減少 Context-switch 數量
• 缺點- 跟 multiple therad 一樣
- 多工效果較差、延遲稍高
︴︴︴︴
Task
Event-Driven
• 常見作法- Single Thread + I/O Multiplexing 或 AIO
• 優點- 單執行緒、沒什麼消耗
- Context-switch 很少
• 缺點
- 無法完整利用硬體
- 一般會有 Callback hell
Event ︴
Handler
Event Loop
More and more
• 人腦就偽雙核心,Multi-Thread 真的很難
• 其他的選擇- Worker, provider + comsumer
- Golang 的 CPS, Goroutine
- Erlang 的 Actor
- Functional Programming (非常適合平行)
- STM memory
- 包好的 Framework. 例如 Netty
做的事情越少越好
• 好用的東西都是犧牲 CPU cycle 做出來的
• 或許有些不必要的分層、抽象- 不要用有 VM 的語言
- 不要用 Active Record
- 不要用 Framework
- 不要用 JSON
- 不要用 HTTP(S)
• 理性勿戰,選擇剛剛好的選項
聰明的做事情
• 設計好工作方式- 避免當傻蛋油漆工
• 選擇適合的演算法、資料結構- 這個不用說…大家都有學好吧!
• 請考慮空間 vs. 時間- 時間有 O(n) 不要用 O(n2)
- 空間有 O(1) 不要用 O(n)
https://en.wikipedia.org/wiki/Road#/media/File:Making_lines_on_the_road.JPG
nginx
• nginx is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server
• Multi-process + 事件驅動 (libevent)
• 跟 OS 做好朋友 (sendfile, mmap)
• 自己做了 cache
• aio thread pool (>=1.7.11)- Thread Pools in NGINX Boost Performance 9x!
Redis
• Redis is an open source (BSD licensed), in-memorydata structure store, used as database, cache and message broker.
• 單執行緒存取、維護資料
• 事件驅動 (aeEventLoop)
• In-memory 儲存資料
• 客製化資料結構
• 背景執行緒,負責持久化
Node.js
• Node.js is a JavaScript runtime uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.
• 單執行緒執行 JavaScript V8 engine
• 事件驅動 (libuv)
- Thread pool 負責 I/O, blocking call
Reference
• http://www.ibm.com/developerworks/library/l-async/
• https://www.amazon.com/Systems-Performance-Enterprise-Brendan-Gregg/dp/0133390098
• http://www.kegel.com/c10k.html
• http://www.gotw.ca/publications/concurrency-ddj.htm
• http://www.brendangregg.com/linuxperf.html