JEUS Thread Pool Bottleneck Analysis
JEUS Thread Pool Bottleneck Analysis
Giới thiệu
Một trong những vấn đề khó chịu nhất trên hệ thống Java là tình trạng người dùng phản ánh hệ thống chậm nhưng CPU không cao và TPS cũng không quá lớn.
Nếu chỉ nhìn CPU hoặc TPS rất dễ kết luận sai nguyên nhân.
Bài viết này ghi lại một trường hợp thực tế khi hệ thống JEUS bị nghẽn vì thread pool đạt giới hạn cấu hình.
Triệu chứng
Tại thời điểm hệ thống bị chậm ghi nhận:
- Active Service = 100
- JEUS Active Thread = 100
- TPS = 57
- Average Response Time = 622 ms
Người dùng phản ánh:
- Màn hình phản hồi chậm
- Có thời điểm timeout
- Số lượng request tăng nhưng tốc độ xử lý không tăng tương ứng
Phân tích dữ liệu
Active Thread
Giá trị Active Thread đã đạt đúng giới hạn cấu hình.
Active Thread = Max Thread
Điều này có nghĩa:
- Mọi worker thread đều đang bận.
- Không còn thread sẵn sàng nhận request mới.
- Request mới phải chờ trong queue.
Đây là dấu hiệu quan trọng nhất.
TPS
Nhiều người thường nghĩ:
TPS thấp
=> Hệ thống chưa quá tải
Điều này không hoàn toàn đúng.
Trong trường hợp này:
TPS = 57
không phải là con số lớn.
Tuy nhiên:
Thread Pool = Full
Điều đó cho thấy vấn đề nằm ở thời gian xử lý mỗi request chứ không phải số lượng request.
Response Time
Response Time trung bình:
622 ms
Nếu hệ thống bình thường chạy trong khoảng:
100 ~ 200 ms
thì mức 622 ms là dấu hiệu bất thường.
Khi mọi thread đều bận:
- Request đang chạy tiếp tục chiếm thread.
- Request mới phải xếp hàng.
- Thời gian chờ tăng lên.
- Response Time tăng theo.
Các giả thuyết cần kiểm tra
SQL chậm
Một câu query chậm có thể giữ thread quá lâu.
Biểu hiện:
- TPS thấp
- DB CPU cao
- Active Thread tăng
Cần kiểm tra:
- Slow Query
- Execution Plan
- Chỉ mục
External Call chậm
Ví dụ:
- REST API
- SOAP
- TCP Socket
- Hệ thống đối tác
Chỉ cần một downstream service phản hồi chậm là toàn bộ thread pool có thể bị chiếm giữ.
Dấu hiệu:
- Response Time tăng
- Active Thread tăng
- TPS không tăng
Blocking
Ví dụ:
synchronized
hoặc lock database.
Dấu hiệu:
- Thread tồn tại lâu
- Nhiều thread chờ lock
Deadlock
Ít gặp hơn nhưng nguy hiểm.
Dấu hiệu:
- Thread dump xuất hiện BLOCKED
- Active Thread luôn cao
Cách điều tra
Bước 1 - Xác định thời điểm nghẽn
Ghi nhận:
- Thời gian
- TPS
- Response Time
- Active Service
Ví dụ:
14:35
TPS = 57
RT = 622 ms
Active Thread = 100
Bước 2 - Xem Profile trong Jennifer
Kiểm tra:
- Service nào tốn thời gian nhất
- SQL nào chậm nhất
- External Call nào chậm nhất
Mục tiêu:
Tìm thành phần chiếm thời gian
không phải tìm component có nhiều request nhất.
Bước 3 - Thu thập Thread Dump
Thu nhiều lần liên tục:
jstack
Ví dụ:
jstack <PID> > dump1.txt
Sau 10 giây:
jstack <PID> > dump2.txt
Nếu cùng một nhóm thread xuất hiện nhiều lần chứng tỏ chúng đang bị giữ quá lâu.
Bước 4 - Kiểm tra Database
Quan sát:
- Active Session
- Wait Event
- Long Running Query
Nhiều trường hợp nghẽn JEUS thực chất là nghẽn Database.
Kết luận cho case này
Dựa trên dữ liệu:
- Active Thread = Max
- TPS không cao
- Response Time tăng
Khả năng lớn là:
- SQL chậm.
- External Call chậm.
- Thread bị block.
Ít có khả năng nguyên nhân là do lượng request quá lớn.
Kinh nghiệm rút ra
Không nên đánh giá tải hệ thống chỉ bằng TPS.
Cần nhìn đồng thời:
- TPS
- Response Time
- Active Service
- Active Thread
- SQL Time
- External Call Time
Bộ chỉ số này cho cái nhìn chính xác hơn rất nhiều so với việc chỉ theo dõi CPU hoặc TPS.
Checklist nhanh
Khi Active Thread đạt Max:
- Ghi nhận TPS
- Ghi nhận Response Time
- Kiểm tra Jennifer Profile
- Kiểm tra External Call
- Kiểm tra SQL
- Thu thập Thread Dump
- Kiểm tra Lock
- Xác định thành phần giữ thread lâu nhất
Lessons Learned
Thread Pool Full không phải là nguyên nhân.
Thread Pool Full là triệu chứng.
Cần tìm ra thành phần nào đang giữ thread lâu bất thường để giải quyết tận gốc vấn đề.