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:

  1. Request đang chạy tiếp tục chiếm thread.
  2. Request mới phải xếp hàng.
  3. Thời gian chờ tăng lên.
  4. 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à:

  1. SQL chậm.
  2. External Call chậm.
  3. 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 đề.