Node.js 淺談筆記

Embarrassingly parallel


透過 manager process 分配工作給 replica process 經典代表: php
看起來很美好, 但有些問題
在做 CPU 密集的工作或是跟IO相關的工作時
該 replica process 就會整個 idle

CPU如果一直在做 context switch 其實也會造成延遲
所以並不是說 worker process 開得越多越好

所以通常都會開核心數的 2 ~ 4 倍的 worker process 來達到充份利用CPU
例如:
4 核心可能會需要開 8 ~ 16 個 worker process
超過這個範圍, 效能不會增加, 反而會下降
因為都會浪費時間在 context switch 上

Node.js 也是類似的方式, 但跟PHP不同的是
Node.js 本身在執行Javascript的部分是單執行緒(single thread),
透過 event queue 來壓榨單顆核心的效能
如果每個 process 都是單執行緒, 那就開核心數個 process
ex:
4 核心就開 4 個 process, 透過這種方法把所有核心榨乾

但是還是有缺點
1. 沒有共享記憶體 (shared memory)
2. 如果有用 connection pool 的機制, connection pool 數會是一般的核心數倍
ex:
node.js 連接 redis 時假設 connection pool 數是設定 20條 connections
4 cores 就會有 20*4 條 connections
有可能會造成很多 idle connections

像是 postgresql
每條 connection 都是一個 process
彼此透過 shared memory
如果某個 process 掛掉了, 不會影響到其他 process
Node.js 也是有類似的好處
一個 process 掛了不影響到其他 process
(Node.js 每個 process有自己的 event queue & connection pool)


Java, Golang 每個 process 會開很多個 thread,
而不是每個 request 開一個 thread
又因為他們有自己的軟體 thread pool
每個 request 會填入 process 開的 thread
比較不會有 context switch, 所以效能會比較好

一個 process 開了很多 thread
要共享變數的話, 可以把變數放在 process lebel
這樣所有的 thread 就可以共用 process variable了

System throttling
最簡單的方式是 rate limiting
但不好的原因是有可能服務用到一半變成 server unavalable,
UX會很差, 假如你在發文發到一半, 按送出的時候跑出 502,
使用者會很幹

如果已經在執行 rate limiting時,
比較好的 rate limiting 的方法是
每個 user 有自己的 token,
把 token 放進 redis 中, 設定過期時間為15分鐘
執行 rate limiting 時, 就不再把 user token 加到 redis 中
此時進來的 request 的 token 如果有在 redis 中
一樣讓這個 request 可以正常使用
沒有的則是一樣不給用
但是會有個問題
最大的問題是, 現在是因為流量的爆增才去做 system throttling
所以可想而知, 要嘛就是 redis cluster 要開很大服務才不會掛
而且很多進去 redis 查詢的 request, 大部分都是要被放棄掉的
所以都是種 server 資源的浪費

推薦閱讀 安德魯大大的文章
https://columns.chicken-house.net/2018/06/10/microservice10-throttle/


17 media使用的方法 - Bloomfilter

假設給 bloomfilter 1 MB 的空間
bloomfilter 可以 add string, 確認 string 是否 exists
所以要做 system throttling的話
可以把 token 放在 bloomfilter 中,
雖然 bloomfilter 本身是會出錯, 但錯誤率可以小於 1%

每台 application server 都有自己的 bloomfilter,
透過 background thread將各自同步給 redis
redis 再同步給所有的 application server



要怎麼知道boomfilter內的token是在15分鐘期限內呢?

可以在boomfilter外包一層

Bloomfilter object內每一分鐘產一個bloomfilter,
超過15個就shift掉,
要檢查的時候再把bloomfilter merge成一個去查

BF會有race condition的問題
永遠不要相信我的語言是atomic
一個讀一個寫的話就會race condition

BFObject同時很多的讀寫

Read比較多
是否存在 有存在的話就不用寫了
通常會用你的系統的人在第一次就寫過了
所有通常會是很多的read

用讀寫鎖的機制解決
因為動作大部分是讀
讀可以parallel執行

所以要寫的時候用寫鎖就好了
但還是會因為寫鎖讓其他讀的thread卡住


Message passing 會把所有東西丟到message queue
只用一個thread去工作就不會有race condition的問題

跨主機用rabbit mq
同主機 golang java 有自己的library
Golang的channel 就是使用 message passing的機制



為啥不在db operate時同時用兩個thread 一邊讀 一邊log

1 因為麻煩
2 如果可以做 會因為thread間通信浪費時間 不會差多少
3 提高throghput比較重要

留言

這個網誌中的熱門文章

[MySQL] schema 與資料類型優化

[翻譯] 介紹現代網路負載平衡與代理伺服器