Dùng Claude Code cho điều tra hiệu năng theo vòng lặp có thể lặp lại: đo, đưa ra giả thuyết, thay đổi tối thiểu và đo lại trước khi phát hành.

Lỗi hiệu năng dẫn đến phỏng đoán. Ai đó nhận ra một trang có cảm giác chậm hoặc API bị timeout, và động thái nhanh nhất là "dọn dẹp" code, thêm cache, hoặc viết lại một vòng lặp. Vấn đề là "cảm thấy chậm" không phải là một metric, và "gọn gàng hơn" không đồng nghĩa với nhanh hơn.
Không đo lường, đội ngũ tiêu tốn giờ thay đổi chỗ không đúng. Đường nóng có thể nằm ở cơ sở dữ liệu, mạng, hoặc một cấp phát bất ngờ, trong khi nhóm mài giũa mã chạy hầu như không phải là nút thắt. Tệ hơn, một thay đổi có vẻ thông minh có thể làm hiệu năng tệ hơn: logging thêm trong vòng lặp chật, cache làm tăng áp lực bộ nhớ, hoặc công việc song song gây tranh chấp lock.
Phỏng đoán còn làm rủi ro hỏng hành vi. Khi bạn thay code để tăng tốc, bạn có thể thay đổi kết quả, xử lý lỗi, thứ tự xử lý, hoặc cơ chế retry. Nếu không kiểm tra lại đúng/sai cùng với tốc độ, bạn có thể "thắng" benchmark trong khi lén lút đưa một bug vào.
Hãy coi hiệu năng như một thí nghiệm, không phải một cuộc tranh luận. Vòng lặp đơn giản và có thể lặp lại:
Nhiều chiến thắng là khiêm tốn: bớt 8% p95, giảm đỉnh bộ nhớ 50 MB, hoặc cắt một truy vấn DB. Những chiến thắng đó vẫn quan trọng, nhưng chỉ khi chúng được đo, xác thực và có thể lặp lại.
Cách này hiệu quả nhất khi là một vòng lặp, không phải một yêu cầu "làm nhanh hơn" một lần. Vòng lặp giữ bạn trung thực vì mọi hành động liên kết với bằng chứng và một con số bạn có thể theo dõi.
Một trình tự rõ ràng:
Mỗi bước bảo vệ bạn khỏi một kiểu tự lừa khác nhau. Đo trước ngăn bạn "sửa" thứ không phải vấn đề thật. Một giả thuyết viết ra ngăn bạn thay năm thứ cùng lúc rồi đoán cái nào quan trọng. Thay đổi tối thiểu giảm rủi ro phá vỡ hành vi hoặc thêm nút thắt mới. Đo lại phát hiện các chiến thắng placebo (ví dụ lần chạy nhanh hơn do cache ấm) và lộ các thoái lui.
"Xong" không phải là cảm giác. Đó là kết quả: metric mục tiêu di chuyển theo hướng đúng, và thay đổi không gây thoái lui rõ rệt (lỗi, bộ nhớ cao hơn, p95 tệ hơn, hay các endpoint lân cận chậm hơn).
Biết khi nào dừng cũng là một phần của quy trình. Dừng khi lợi ích phẳng lại, khi metric đã đủ tốt cho người dùng, hoặc khi ý tưởng tiếp theo cần refactor lớn cho lợi ích nhỏ. Công việc hiệu năng luôn có chi phí cơ hội; vòng lặp giúp bạn dành thời gian ở nơi có lợi nhất.
Nếu bạn đo năm thứ cùng lúc, bạn sẽ không biết cái nào cải thiện. Chọn một metric chính cho cuộc điều tra này và coi mọi thứ khác là tín hiệu phụ. Với nhiều vấn đề hướng tới người dùng, metric đó là độ trễ. Với công việc theo lô có thể là thông lượng, thời gian CPU, bộ nhớ, hoặc thậm chí chi phí cloud cho mỗi lần chạy.
Cụ thể về kịch bản. "API chậm" quá mơ hồ. "POST /checkout với giỏ hàng điển hình 3 món" thì có thể đo. Giữ input ổn định để các số có ý nghĩa.
Viết baseline và chi tiết môi trường trước khi đụng vào code: kích thước dataset, loại máy, chế độ build, feature flags, concurrency, và warmup. Baseline này là mỏ neo của bạn. Không có nó, mọi thay đổi có thể trông như tiến bộ.
Với độ trễ, dựa vào phân vị, không chỉ trung bình. p50 cho thấy trải nghiệm điển hình, trong khi p95 và p99 lộ phần đuôi đau đớn mà người dùng phàn nàn. Một thay đổi cải thiện p50 nhưng làm p99 tệ hơn vẫn có thể cảm giác chậm hơn.
Quyết định trước thế nào là "có ý nghĩa" để bạn không ăn mừng nhiễu:
Khi những quy tắc này đã đặt ra, bạn có thể thử ý tưởng mà không dời mục tiêu.
Bắt đầu với tín hiệu đơn giản nhất bạn có thể tin tưởng. Một thời gian đo duy nhất quanh một request có thể cho biết bạn có vấn đề thật hay không, và mức độ khoảng bao nhiêu. Dành profiling sâu hơn khi bạn cần giải thích vì sao nó chậm.
Bằng chứng tốt thường đến từ hỗn hợp nguồn:
Dùng metric đơn giản khi câu hỏi là "nó có chậm hơn và chậm bao nhiêu?" Dùng profiling khi câu hỏi là "thời gian đang đi đâu?" Nếu p95 gấp đôi sau deploy, bắt đầu với timing và log để xác nhận thoái lui và khoanh vùng. Nếu timing cho thấy phần lớn độ trễ nằm trong code app (không phải DB), thì một profiler CPU hoặc flame graph có thể chỉ ra hàm chính xác tăng thời gian.
Giữ việc đo an toàn. Thu thập những gì cần để debug hiệu năng, không phải nội dung người dùng. Ưu tiên tổng hợp (durations, counts, sizes) hơn payload thô, và redact định danh theo mặc định.
Nhiễu có thật, nên lấy nhiều mẫu và ghi ra ngoại lệ. Chạy cùng request 10–30 lần, và ghi median và p95 thay vì một lần chạy tốt nhất.
Viết lại chính xác kịch bản thử nghiệm để có thể lặp: môi trường, dataset, endpoint, kích thước body, mức concurrency, và cách bạn ghi nhận kết quả.
Bắt đầu với một triệu chứng bạn có thể đặt tên: "p95 latency nhảy từ 220 ms lên 900 ms trong giờ cao điểm", "CPU đứng ở 95% trên hai lõi", hoặc "bộ nhớ tăng 200 MB mỗi giờ." Triệu chứng mơ hồ như "cảm thấy chậm" dẫn tới thay đổi ngẫu nhiên.
Tiếp theo, chuyển những gì bạn đo thành khu vực nghi ngờ. Một flame graph có thể cho thấy phần lớn thời gian ở JSON encoding, một trace có thể cho thấy một đường gọi chậm, hoặc thống kê DB có thể cho thấy một truy vấn chiếm phần lớn thời gian. Chọn phần nhỏ nhất giải thích phần lớn chi phí: một hàm, một câu SQL, hoặc một cuộc gọi ngoài.
Một giả thuyết tốt là một câu, có thể kiểm tra và gắn với một dự đoán. Bạn đang xin phép thử một ý tưởng, không yêu cầu công cụ làm tất cả nhanh hơn phép thuật.
Dùng định dạng này:
Ví dụ: "Bởi vì profile cho thấy 38% CPU nằm trong SerializeResponse, cấp phát buffer mới mỗi request đang gây spike CPU. Nếu ta tái sử dụng buffer, p95 latency nên giảm khoảng 10–20% và CPU nên giảm 15% dưới cùng tải."
Giữ trung thực bằng cách đặt tên các giải thích thay thế trước khi chạm code. Có thể phần chậm thực ra là dependency upstream, contention lock, thay đổi tỉ lệ cache miss, hoặc một rollout làm tăng kích thước payload.
Viết ra 2–3 giải thích thay thế, sau đó chọn cái bằng chứng ủng hộ nhất. Nếu thay đổi không di chuyển metric, bạn đã có giả thuyết tiếp theo sẵn sàng.
Claude hữu ích nhất trong công việc hiệu năng khi bạn đối xử nó như một nhà phân tích thận trọng, không phải một nhà tiên tri. Giữ mọi đề xuất gắn với những gì bạn đo, và đảm bảo mỗi bước có thể bị bác bỏ.
Cho nó đầu vào thực, không mô tả mơ hồ. Dán bằng chứng nhỏ, tập trung: tóm tắt profiling, vài dòng log quanh request chậm, một query plan, và đường dẫn code cụ thể. Bao gồm số "trước" (p95 latency, thời gian CPU, thời gian DB) để nó biết baseline của bạn.
Hỏi nó giải thích dữ liệu gợi ý gì và không gợi ý gì. Rồi ép xuất các giải thích cạnh tranh. Một prompt hữu ích kết thúc bằng: "Cho tôi 2–3 giả thuyết, và với mỗi giả thuyết, nói cách bác bỏ nó." Điều đó ngăn việc dính vào câu chuyện hợp lý đầu tiên.
Trước khi thay gì, hỏi cho thử nghiệm nhỏ nhất có thể xác thực giả thuyết hàng đầu. Giữ nó nhanh và có thể hoàn tác: thêm một timer quanh hàm, bật một flag profiler, hoặc chạy một câu truy vấn với EXPLAIN.
Nếu bạn muốn cấu trúc chặt cho đầu ra, hãy yêu cầu:
Nếu nó không thể nêu metric cụ thể, vị trí, và kết quả mong đợi, bạn lại đang đoán mò.
Sau khi có bằng chứng và giả thuyết, kìm ham muốn "dọn dẹp mọi thứ." Công việc hiệu năng dễ tin nhất khi thay đổi nhỏ và dễ hoàn tác.
Thay một điều tại một thời điểm. Nếu bạn chỉnh query, thêm cache, và refactor loop trong cùng một commit, bạn sẽ không biết cái nào có tác dụng (hoặc gây hại). Thay đổi đơn biến khiến phép đo tiếp theo có ý nghĩa.
Trước khi chạm code, viết ra mong đợi bằng số. Ví dụ: "p95 latency giảm từ 420 ms xuống dưới 300 ms, và thời gian DB giảm khoảng 100 ms." Nếu kết quả không đạt, bạn nhanh chóng biết giả thuyết yếu hoặc thiếu.
Giữ thay đổi có thể hoàn tác:
"Tối thiểu" không có nghĩa là "tầm thường." Nó có nghĩa là tập trung: cache một hàm tốn kém, loại bỏ một cấp phát lặp trong vòng chặt, hoặc dừng làm việc cho các request không cần.
Thêm thời gian đo nhẹ quanh nút nghi ngờ để thấy điều gì di chuyển. Một timestamp trước và sau một call (log hoặc gửi làm metric) có thể xác nhận thay đổi đánh đúng chỗ hay chỉ chuyển thời gian sang chỗ khác.
Sau thay đổi, chạy lại đúng kịch bản bạn dùng cho baseline: cùng input, môi trường, và hình dạng tải. Nếu test bạn lệ thuộc vào cache hoặc warm-up, ghi rõ (ví dụ: "lần chạy đầu cold, 5 lần sau warm"). Nếu không, bạn sẽ "tìm thấy" cải thiện chỉ do may mắn.
So sánh kết quả dùng cùng metric và cùng phân vị. Trung bình có thể che giấu vấn đề, nên theo dõi p95 và p99, cùng throughput và thời gian CPU. Chạy đủ số lặp để thấy con số ổn định.
Trước khi ăn mừng, kiểm tra các thoái lui không hiện trong một số headline:
Rồi quyết định dựa trên bằng chứng, không phải hy vọng. Nếu cải thiện thật và không gây regressions, giữ thay đổi. Nếu kết quả lẫn lộn hoặc nhiễu, revert và lập giả thuyết mới, hoặc thu hẹp thay đổi hơn.
Nếu bạn làm việc trên nền tảng như Koder.ai, chụp snapshot trước khi thí nghiệm có thể biến rollback thành một bước duy nhất, làm cho việc thử ý tưởng táo bạo an toàn hơn.
Cuối cùng, viết ra những gì bạn học được: baseline, thay đổi, số mới, và kết luận. Bản ghi ngắn này tránh lặp lại cùng ngõ cụt ở vòng sau.
Công việc hiệu năng thường sai khi bạn đánh mất sợi chỉ giữa điều đo và điều thay. Giữ một chuỗi bằng chứng sạch để bạn có thể nói chắc chắn điều gì làm tốt hơn hoặc tệ hơn.
Những kẻ phạm tội lặp lại:
Một ví dụ nhỏ: một endpoint trông chậm, bạn tinh chỉnh serializer vì nó nóng trong profile. Rồi bạn test lại với dataset nhỏ hơn và thấy nhanh hơn. Ở production p99 tệ hơn vì DB vẫn là nút thắt và thay đổi của bạn tăng kích thước payload.
Nếu dùng Claude Code để đề xuất sửa, xích nó sát lại. Yêu cầu 1–2 thay đổi tối thiểu phù hợp với bằng chứng bạn thu thập, và kiên quyết với kế hoạch đo lại trước khi chấp nhận patch.
Những tuyên bố tốc độ sụp đổ khi test mơ hồ. Trước khi ăn mừng, đảm bảo bạn có thể giải thích bạn đo gì, cách đo, và bạn thay gì.
Bắt đầu bằng việc đặt tên một metric và ghi baseline. Bao gồm các chi tiết làm thay đổi con số: loại máy, tải CPU, kích thước data, chế độ build (debug vs release), feature flags, trạng thái cache, và concurrency. Nếu bạn không thể tái tạo cấu hình ngày mai, bạn không có baseline.
Checklist:
Sau khi số tốt hơn, làm một kiểm tra hồi quy nhanh. Kiểm tra đúng đắn (same outputs), tỉ lệ lỗi, và timeouts. Quan sát tác dụng phụ như bộ nhớ lớn hơn, spike CPU, khởi động chậm hơn, hoặc tải DB tăng. Thay đổi cải thiện p95 nhưng tăng gấp đôi bộ nhớ có thể là đánh đổi sai.
Một nhóm báo rằng GET /orders ổn trong dev, nhưng chậm ở staging khi tải vừa phải. Người dùng phàn nàn timeouts, nhưng trung bình độ trễ vẫn trông "ổn", đây là cái bẫy kinh điển.
Đầu tiên, đặt baseline. Dưới một thử tải ổn định (cùng dataset, cùng concurrency, cùng thời lượng), bạn ghi:
Bây giờ thu thập bằng chứng. Một trace nhanh cho thấy endpoint chạy một truy vấn chính cho orders, rồi lặp và fetch các item liên quan cho mỗi order. Bạn cũng thấy response JSON lớn, nhưng thời gian DB chiếm ưu thế.
Biến đó thành danh sách giả thuyết có thể kiểm tra:
Yêu cầu một thay đổi tối thiểu phù hợp bằng chứng mạnh nhất: loại bỏ một cuộc gọi N+1 rõ ràng bằng cách fetch items trong một truy vấn duy nhất theo order IDs (hoặc thêm index nếu kế hoạch truy vấn cho thấy full scan). Giữ reversible và commit có scope rõ.
Đo lại với cùng thử tải. Kết quả:
Quyết định: ship fix (clear win), sau đó bắt đầu vòng hai tập trung vào khoảng trống còn lại và spike CPU, vì DB không còn là giới hạn chính nữa.
Cách nhanh nhất để làm tốt hơn trong điều tra hiệu năng là coi mỗi lần chạy như một thí nghiệm nhỏ có thể lặp lại. Khi quy trình nhất quán, kết quả dễ tin cậy, so sánh và chia sẻ hơn.
Một mẫu một trang đơn giản giúp:
Quyết định nơi lưu các ghi chú này để không mất. Nơi chung quan trọng hơn công cụ hoàn hảo: một thư mục repo cạnh service, một tài liệu nhóm, hoặc ghi chú ticket. Điểm then chốt là dễ tìm. Ai đó nên có thể tìm "p95 latency spike sau thay đổi cache" vài tháng sau.
Biến các thí nghiệm an toàn thành thói quen. Dùng snapshot và rollback dễ để thử ý tưởng không sợ. Nếu bạn xây với Koder.ai, Planning Mode là nơi tiện để phác thảo kế hoạch đo, định nghĩa giả thuyết, và giữ scope trước khi sinh diff chặt và đo lại.
Đặt nhịp. Đừng chờ sự cố. Thêm kiểm tra hiệu năng nhỏ sau các thay đổi như truy vấn mới, endpoint mới, payload lớn hơn, hoặc nâng cấp dependency. Một check baseline 10 phút giờ có thể cứu bạn một ngày đoán mò sau đó.
Bắt đầu với một con số phù hợp với lời phàn nàn, thường là độ trễ p95 cho một endpoint và input cụ thể. Ghi baseline dưới cùng điều kiện (kích thước dữ liệu, concurrency, cache ấm/lạnh), rồi thay đổi một thứ và đo lại.
Nếu bạn không thể tái tạo baseline, nghĩa là bạn chưa đang đo — bạn đang đoán mò.
Một baseline hữu ích bao gồm:
Ghi nó xuống trước khi bạn chạm vào code để không đổi mục tiêu.
Các phân vị cho thấy trải nghiệm người dùng rõ hơn trung bình. p50 là “thông thường,” nhưng người dùng phàn nàn về phía đuôi, tức p95/p99.
Nếu p50 tốt hơn nhưng p99 tệ hơn, hệ thống vẫn có thể cảm thấy chậm dù trung bình trông ổn.
Dùng các thời gian/log đơn giản khi bạn hỏi “nó có chậm hơn và chậm bao nhiêu?” Dùng profiling khi câu hỏi là “thời gian đang đi đâu?”
Luồng thực tế: xác nhận suy giảm bằng timing, rồi profile sau khi biết chậm thực sự và đã khoanh vùng.
Chọn một metric chính, và coi phần còn lại như các guardrail. Một tổ hợp phổ biến là:
Cách này tránh việc “thắng” trên một biểu đồ trong khi âm thầm gây lỗi/timeouts hoặc độ trễ đuôi tệ hơn.
Viết một giả thuyết một câu liên kết với bằng chứng và một dự đoán:
Nếu bạn không thể nêu bằng chứng và mức di chuyển kỳ vọng của metric, giả thuyết chưa thể kiểm tra được.
Hãy nhỏ và dễ hoàn tác:
Diff nhỏ giúp phép đo tiếp theo có ý nghĩa và giảm rủi ro làm vỡ hành vi khi chạy cùng lúc nhiều thay đổi.
Chạy lại cùng kịch bản baseline (cùng input, môi trường, hình dạng tải). Sau đó kiểm tra các hồi quy không hiện ra ở số headline:
Nếu kết quả nhiễu, lấy nhiều mẫu hơn hoặc revert và thu hẹp thí nghiệm.
Cho đầu vào cụ thể và ép nó theo hướng kiểm chứng:
Nếu đầu ra không nêu metric cụ thể và kế hoạch đo lại, bạn đang trở lại đoán mò.
Dừng khi:
Công việc hiệu năng có chi phí cơ hội. Vòng (đo → giả thuyết → thay đổi → đo lại) giúp bạn chỉ dành thời gian ở nơi các con số chứng minh đáng làm.