Storm中Spout用於讀取並向計算拓撲中發送數據源,最近在調試一個topology時遇到了系統qps低,處理速度達不到要求的問題,經過排查后發現是由於對Spout的使用模式不當導致的多線程同步等待。這里羅列幾點個人覺得編寫Spout代碼時需要特別注意的地方:
1. 最常用的模式是使用一個線程安全的queue,如BlockingQueue,spout主線程從queue中讀取數據;另外的一個或多個線程負責從數據源(如各種消息中間件、db等)讀取數據並放入queue中。
2. 如果不關心數據是否丟失(例如數據統計分析的典型場景),不要啟用ack機制。
3. Spout的nextTuple和ack方法是在同一個線程中被執行的(可能最初覺得這塊不會成為瓶頸,為了簡單實現起見就單線程了,jstorm應該是已經改成了多線程),因此不能在nextTuple或ack方法里block住當前線程,這樣將直接影響spout的處理速度,很關鍵。
4. Spout的nextTuple發送數據時,不能阻塞當前線程(見上一條),比如從queue中取數據時,使用poll接口而不是take,且poll方法盡量不要傳參阻塞固定時間,如果queue中沒有數據則直接返回;如果有多條待發送的數據,則一次調用nextTuple時遍歷全部發出去。
5. Spout從0.8.1之后在調用nextTuple方法時,如果沒有emit tuple,那么默認需要休眠1ms,這個具體的策略是可配置的,因此可以根據自己的具體場景,進行設置,以達到合理利用cpu資源。