30 câu hỏi RabbitMQ và Kafka
Luyện theo architecture → failure window → guarantee scope → operational evidence. Chọn một câu, tự trả lời trong 60–90 giây trước khi mở đáp án; sau đó chỉ ra một điểm crash, một đánh đổi và bằng chứng cần thu thập để kiểm tra kết luận của mình.
Đừng dừng ở tên API hoặc “bật cấu hình này là an toàn”. Hãy nói rõ ai đang giữ trách nhiệm, business invariant cần bảo vệ, crash xảy ra giữa hai bước nào, và guarantee có hiệu lực đến đâu. Với exactly-once, luôn nêu scope và assumptions; với ack/offset, tách trạng thái delivery/checkpoint của broker khỏi side effect trong DB/payment/email. Kết thúc bằng metric, trace hoặc failure test có tiêu chí đạt.
Phạm vi đọc: RabbitMQ queues qua AMQP 0-9-1 và KafkaConsumer groups theo mô hình gán partition; không đánh đồng với RabbitMQ Streams hay Kafka share groups. “Trả lời ngắn” giữ nguyên ý nguồn; phần bên dưới làm rõ điều kiện và ngoại lệ. Production evidence là bài thử đề xuất và tiêu chí kiểm chứng, không phải số liệu hay kết quả test đã thực hiện. Thực hiện fault injection trong môi trường thử nghiệm cô lập, có dữ liệu giả lập và kế hoạch khôi phục. Mở từng câu bằng chuột, hoặc dùng Tab rồi Enter/Space; có thể mở nhiều câu để so sánh. Xem bản đồ 10 chương.
01. RabbitMQ
Câu 1–10 · 10 câuĐi từ routing và delivery đến durability, quorum, retry/DLQ và backpressure. Luôn tách producer handoff khỏi consumer processing.
1.Exchange, binding và queue khác nhau?
Exchange route publish theo binding; queue giữ delivery; consumer đọc queue. Producer không cần biết consumer.
- Mental model
Hình dung exchange là bộ định tuyến, binding là luật, queue là nơi giữ delivery. Direct khớp routing key; topic khớp mẫu; fanout phát đến các queue đã bind. Nhiều consumer cùng queue chia việc, còn hai queue độc lập có thể nhận hai bản sao của cùng event. Producer phụ thuộc contract routing, không cần biết instance consumer.
- Failure window
Publish vào exchange thành công chưa chứng minh message đã tới queue mong muốn. Binding thiếu hoặc routing key sai có thể tạo message không được route. Với AMQP 0-9-1, dùng
mandatoryvà xử lýbasic.returnđể phát hiện unroutable; publisher confirm không thay kiểm tra này.- Trade-off
Một queue chia việc giúp giảm số bản sao nhưng không tạo subscription độc lập cho từng service. Mỗi service một queue cho phép tốc độ xử lý riêng, đổi lại tốn storage và phải quản lý thêm topology, permissions, lifecycle. Không tạo queue mới chỉ để che việc consumer cũ không theo kịp.
- Production evidence
Bài thử: tạo hai queue có binding rõ ràng, gửi các event ID đã biết, rồi cố ý dùng một routing key không khớp. Thu binding snapshot, publish/return counters và tập event ID mỗi queue. Tiêu chí: phân biệt được routing đúng, fan-out dự kiến và unroutable; không suy luận từ log “send thành công”.
2.Publisher confirm khác consumer ack?
Confirm bảo vệ handoff producer–broker; ack bảo vệ broker–consumer. Cả hai không atomic với DB side effect.
- Mental model
Có hai lần bàn giao trách nhiệm: confirm cho producer → broker, ack cho delivery broker → consumer. Confirm không nói consumer đã chạy; consumer ack không chứng minh DB đã commit. Hai cơ chế độc lập, đều không tạo transaction chung với side effect bên ngoài broker.
- Failure window
Broker nhận publish nhưng confirm mất trên mạng: producer chưa biết kết quả, gửi lại có thể trùng. Consumer commit DB rồi chết trước ack: broker có thể giao lại và DB bị cập nhật lần nữa. Ack trước DB commit lại mở cửa sổ mất xử lý nghiệp vụ nếu consumer crash.
- Trade-off
Manual ack sau khi side effect đã được ghi bền vững giảm loss window nhưng chấp nhận redelivery. Dùng idempotent consumer; nếu cần đồng bộ business transaction với publish, dùng transactional outbox và relay. Chờ từng confirm đơn giản nhưng giảm pipeline; xử lý confirm bất đồng bộ cần theo dõi từng publish chưa rõ kết quả.
- Production evidence
Bài thử: ngắt kết nối sau publish và kill consumer ngay sau DB commit, trước ack. Nối trace theo event ID qua publish attempt, confirm, delivery attempt và DB transaction. Tiêu chí: có thể thấy nhiều delivery nhưng chỉ một business effect đã commit; luôn tách broker evidence khỏi business evidence.
3.Vì sao ack phải cùng channel?
Delivery tag chỉ unique trong channel; ack channel khác gây protocol error và đóng channel.
- Mental model
Delivery tag là số thứ tự cục bộ của channel, không phải message ID toàn hệ thống. Một delivery phải được ack/nack trên chính channel nhận nó. Giữ context gồm channel, tag và trạng thái xử lý; không chuyển mỗi tag sang một channel bất kỳ trong pool để xác nhận.
- Failure window
Ack sai channel hoặc ack lại tag đã hoàn tất có thể gây
PRECONDITION_FAILEDvà đóng channel. Những delivery khác còn unacked trên channel đó có thể được giao lại. Khi xử lý song song,multiple=truecòn có thể ack cả tag nhỏ hơn dù tác vụ tương ứng chưa xong.- Trade-off
Ack từng delivery dễ kiểm soát completion nhưng tăng số frame. Batch ack giảm overhead chỉ khi mọi tag được bao phủ đã thực sự hoàn tất. Hướng thiết kế an toàn là điều phối ack theo ownership của channel và quy tắc thread-safety của client, không mặc định mọi thao tác channel đều dùng chung thread được.
- Production evidence
Bài thử: nhận trên channel A, cố ý ack bằng B, rồi thử hoàn thành task lệch thứ tự. Thu channel-close reason, delivery tags và danh sách task còn chạy. Tiêu chí: đường xử lý đúng không có unknown-tag, không ack nhầm việc chưa xong; đóng channel không làm nhân đôi business effect.
4.Auto-ack có rủi ro gì?
Broker coi delivery hoàn tất trước xử lý; crash gây mất và consumer chậm có thể tích backlog memory.
- Mental model
Auto-ack nghĩa là broker không giữ delivery ở trạng thái chờ xác nhận xử lý của ứng dụng. Đây là hoàn tất ở tầng delivery, không phải hoàn tất nghiệp vụ. Nếu client nhận nhanh hơn handler xử lý, backlog có thể nằm trong buffer hoặc bộ nhớ của consumer thay vì hiện rõ ở queue.
- Failure window
Consumer nhận message rồi crash trước khi ghi DB: broker không có unacked delivery đó để giao lại theo cơ chế manual ack. Handler chậm cũng có thể làm bộ nhớ tăng cho tới OOM. Hàng đợi phía broker giảm không chứng minh ứng dụng đã xử lý hết.
- Trade-off
Auto-ack bớt bookkeeping và có thể phù hợp dữ liệu có thể bỏ qua theo yêu cầu đã thống nhất. Với công việc không được mất, chọn manual ack và bounded concurrency/buffer. Prefetch dùng để giới hạn unacked delivery trong manual-ack flow; không coi nó là hàng rào bảo vệ tương đương khi auto-ack.
- Production evidence
Bài thử: làm chậm handler, theo dõi số received so với số business-completed, rồi kill process. So sánh số event thiếu sau restart giữa auto-ack và manual ack. Thu RSS/heap, local buffer depth và redelivery. Tiêu chí phải dựa trên tập event ID nghiệp vụ, không chỉ queue depth bằng 0.
5.Prefetch ảnh hưởng throughput/fairness?
Cao tăng pipeline nhưng giữ nhiều unacked ở một consumer; thấp tăng round trip. Tune theo latency, payload và concurrency.
- Mental model
Prefetch là giới hạn số delivery chưa ack, không phải số thread. Nó tạo cửa sổ để broker và consumer chạy chồng lấp. Trong RabbitMQ, cần đọc đúng scope cấu hình theo consumer/channel và client đang dùng; tăng prefetch không tự tăng số handler thực thi đồng thời.
- Failure window
Prefetch lớn khiến một consumer giữ nhiều việc: nó crash thì nhiều delivery cần phát lại; nó chậm thì consumer khác có thể thiếu việc. Prefetch quá thấp làm pipeline thường xuyên chờ ack/network round trip, đặc biệt khi handler nhanh hoặc độ trễ mạng lớn.
- Trade-off
Tune đồng thời prefetch, concurrency, payload size và downstream latency. Có thể bắt đầu gần số handler đồng thời rồi tăng có kiểm soát để bù độ trễ, nhưng không có giá trị tối ưu chung. Giữ trần memory và số request downstream; ưu tiên phân phối công bằng khi thời gian task biến động mạnh.
- Production evidence
Bài thử: chạy cùng payload/workload với vài mức prefetch, gồm cả task chậm và task nhanh. So throughput, p95/p99 processing age, unacked mỗi consumer, memory và độ lệch phân phối. Sau đó kill một consumer. Tiêu chí: mức chọn vẫn đạt SLO và recovery budget, không chỉ đạt throughput cao nhất.
6.Durable queue có đủ chống mất message?
Không; còn cần persistent publish, confirm và HA phù hợp. Durability topology chỉ giúp queue sống qua restart.
- Mental model
Tách ba lớp: topology sống qua restart, message được lưu bền vững, bản sao sống qua lỗi node. Với classic durable queue, publish persistent và publisher confirm là các phần khác nhau của độ tin cậy. Quorum queue có persistence/replication theo mô hình riêng; không suy ra mọi queue trong cluster đều được replicate.
- Failure window
Queue có thể được khôi phục nhưng message chưa được lưu an toàn thì không. Node lưu bản duy nhất có thể mất disk. Producer crash giữa DB commit và publish vẫn làm thiếu event dù broker rất bền. TTL, overflow policy hoặc thao tác xóa cũng có thể loại message đúng theo cấu hình.
- Trade-off
Persistence, confirms và replication tăng chi phí IO, latency và vận hành. Chọn theo loss tolerance, failure domain và recovery objective, thay vì chỉ bật
durable=true. Dùng outbox cho khoảng trống DB–publish; dùng consumer idempotency cho khoảng trống DB–ack. Không hạ durability để chữa backlog mà chưa đổi yêu cầu nghiệp vụ.- Production evidence
Bài thử: ghi lại các event đã được confirm, restart broker và mô phỏng mất một node trong môi trường thử. Đối chiếu các ID chưa được consume với dữ liệu khôi phục, policy TTL/overflow và trạng thái replica. Tiêu chí: kết luận nêu rõ queue type, failure model và tập message đã confirm; không tuyên bố chống mọi mất dữ liệu.
7.Quorum queue trade-off?
Replicated log tăng safety/HA nhưng tăng IO/network; majority cần hoạt động nên partition có thể giảm availability.
- Mental model
Quorum queue là replicated log sử dụng consensus: leader nhận thao tác và cần đa số thành viên của chính queue để tiến triển. Ví dụ ba replica cần hai replica hoạt động và liên lạc được. Số node toàn cluster không đồng nghĩa số replica hay quorum của từng queue.
- Failure window
Mất leader cần election; trong thời gian đó latency/availability có thể giảm. Mất majority làm queue không thể tiếp tục thao tác bình thường, dù một node vẫn còn sống. Xóa dữ liệu đa số replica hoặc đặt các replica trong cùng failure domain có thể vượt khả năng chịu lỗi đã thiết kế.
- Trade-off
Safety và khả năng chịu lỗi node đổi lấy replication IO/network, disk và latency phối hợp. Thêm replica không mặc nhiên tăng throughput. Chọn placement theo failure domain, để headroom khi một node hỏng và kiểm tra quorum trước rolling maintenance; đừng ép hệ thống bỏ safety chỉ để trả lời nhanh hơn.
- Production evidence
Bài thử: với cấu hình ba replica trong lab, tắt leader rồi tắt thêm replica thứ hai. Ghi thời gian election, confirm latency, mức availability và tập message đã confirm. Tiêu chí: chịu được lỗi trong budget đã định; mất majority phải được phát hiện/alert, không bị mô tả sai thành “HA nên vẫn luôn ghi được”.
8.Requeue loop hình thành thế nào?
Consumer nack requeue ngay khi lỗi còn tồn tại, message quay lại liên tục, đốt CPU/network và starve queue.
- Mental model
Requeue ngay không phải delayed retry. Khi mọi consumer cùng gặp lỗi còn tồn tại,
nack(requeue=true)có thể tạo vòng nhận → lỗi → trả lại → nhận tiếp. Poison message hoặc downstream outage khi đó tiêu hao tài nguyên nhưng không tạo tiến bộ nghiệp vụ.- Failure window
Retry lặp có thể làm nghẽn CPU/network, chiếm delivery window và bỏ đói message tốt. Nếu ứng dụng tự publish sang retry queue rồi ack bản cũ, crash giữa hai thao tác có thể tạo duplicate; ack bản cũ trước khi bàn giao bền vững có thể gây loss.
- Trade-off
Phân loại lỗi transient/permanent; dùng backoff có jitter, số lần thử hữu hạn và parking lot. TTL + DLX là một cách xây retry delay, không phải lịch hẹn chính xác tuyệt đối. Chọn cơ chế có semantics bàn giao rõ; không mặc định mọi DLX đều chuyển an toàn hoặc mọi vòng lặp sẽ được broker cứu.
- Production evidence
Bài thử: gửi một poison event giữa các event tốt và mô phỏng downstream ngừng đáp ứng. Thu attempt count theo ID, tốc độ redelivery, CPU và tuổi message tốt. Tiêu chí: retry kết thúc hoặc cách ly sau giới hạn, không tạo hot loop; những event khác vẫn đạt mức tiến triển đã đặt.
9.Thiết kế DLQ tốt gồm gì?
Bounded attempts, metadata lỗi/trace/original route, alert, owner, replay tool có dry-run/rate limit và idempotency.
- Mental model
DLX là exchange dùng để định tuyến message bị dead-letter; DLQ là queue đích được bind để giữ chúng. DLQ tốt là quy trình vận hành: giới hạn attempts, error class, original route, event/trace ID, timestamps, owner, alert và replay có kiểm soát. Tránh đưa secret/PII thừa vào metadata lỗi.
- Failure window
Dead-letter transfer cũng có thể thất bại. DLX mặc định không phải lời hứa không mất dữ liệu; quorum queue có chế độ at-least-once dead-lettering với điều kiện cấu hình cụ thể. Ngay cả chuyển theo at-least-once vẫn có thể trùng ở đích. Replay hàng loạt có thể lặp side effect hoặc đánh sập downstream vừa hồi phục.
- Trade-off
Tách retry tự động khỏi parking lot cần người xử lý. Replay tool nên có dry-run, lọc nguyên nhân/phiên bản schema, rate limit, canary, audit và kill switch. Giữ cùng business/event ID để dedupe; lưu attempt/replay ID riêng. Retention và dung lượng DLQ phải đủ cho thời gian điều tra, không phải lưu vô hạn.
- Production evidence
Bài thử: làm đích DLQ không sẵn sàng, phát poison event, rồi phục hồi và replay một lô canary. Thu source/target count, age, lỗi chuyển, duplicate và kết quả DB. Tiêu chí: mọi ID được giải trình; dry-run không tạo side effect; owner có thể dừng replay khi error rate tăng.
10.Queue depth tăng cần điều tra gì?
Arrival vs ack rate, processing age, unacked, poison, downstream latency, broker alarms và consumer capacity.
- Mental model
Queue depth là tồn kho; phải nhìn thêm tốc độ vào/ra và tuổi công việc. Phân biệt ready với unacked, processing success với ack rate, và công suất broker với công suất downstream. Depth tăng có thể là burst hợp lệ, thiếu consumer, poison message hoặc consumer không hoàn tất được việc.
- Failure window
DB chậm có thể làm unacked tăng trước khi ready tăng. Consumer tự ack sớm khiến ready nhỏ dù backlog đã chuyển sang ứng dụng. Memory/disk alarms có thể chặn publishing; tăng producer retry lúc này dễ khuếch đại incident. Chỉ scale consumer có thể làm DB quá tải nặng hơn.
- Trade-off
Ưu tiên ổn định hệ thống: hạn chế ingress/retry, xác định bottleneck rồi mới tune. Nếu tốc độ xử lý bền vững là μ và tốc độ vào là λ, ước lượng thời gian drain ≈ backlog/(μ−λ) chỉ có nghĩa khi μ>λ và tốc độ gần ổn định. Đó là mô hình capacity, không phải guarantee.
- Production evidence
Bài thử: tạo burst rồi làm chậm downstream riêng biệt. Thu arrival/ack/success rate, oldest processing age, ready/unacked, consumer capacity, DB latency, disk/memory alarms. Tiêu chí: phân loại được nguyên nhân, chứng minh backlog giảm sau can thiệp và business success hồi phục; không chỉ làm dashboard queue xanh trở lại.
02. Kafka
Câu 11–20 · 10 câuĐi từ partitioned log và ordering đến offsets, consumer groups, replication, idempotent producer và transaction boundary.
11.Vì sao ordering chỉ trong partition?
Mỗi partition là log độc lập có leader và offset; không có total order giữa partitions.
- Mental model
Mỗi partition là một log có thứ tự offset riêng và một leader tại một thời điểm. Vì các log tiến triển độc lập, offset ở partition A không thể dùng để xếp thứ tự với offset ở B. Thứ tự record trong log cũng không tự bảo đảm thứ tự hoàn tất side effect khi handler chạy song song.
- Failure window
Hai event cùng entity đi sang hai partition có thể đến consumer theo thứ tự khác mong muốn. Ngay trong một partition, task xử lý event sau có thể hoàn tất trước task trước. Retry của producer với cấu hình không bảo vệ ordering cũng có thể thay đổi thứ tự ghi trong những tình huống nhất định.
- Trade-off
Global order thường ép đường xử lý vào một partition hoặc một tầng sequencing, giới hạn parallelism. Per-entity order thường thực dụng hơn: dùng key ổn định, xử lý tuần tự theo key và kiểm tra entity version. Trước khi tối ưu, phải phân biệt producer order, broker log order và business apply order.
- Production evidence
Bài thử: phát event có
entityIdvàsequence, đồng thời cố ý làm chậm một handler. Thu partition/offset và thời điểm apply DB. Tiêu chí: sequence được áp dụng đúng trong scope đã cam kết; các event khác partition không bị hiểu nhầm là có total order chỉ vì timestamps gần nhau.
12.Key ảnh hưởng gì?
Quyết định partition, entity ordering và locality; key skew tạo hot partition.
- Mental model
Key là đầu vào cho chiến lược chọn partition và có thể giúp giữ các event cùng entity gần nhau. Cam kết “cùng key → cùng partition” phụ thuộc partitioner, cách serialize key, số partition và việc có chỉ định partition trực tiếp. Key cũng xác định đơn vị ordering/local state, không chỉ là metadata.
- Failure window
Một khách hàng rất lớn tạo hot key: một partition bị quá tải dù toàn cluster còn rảnh. Đổi số partition hoặc cách hash/serialize có thể đưa event mới của cùng key sang partition khác; event cũ còn backlog nên business order có thể bị đảo trong giai đoạn chuyển đổi.
- Trade-off
Chọn key đủ phân tán nhưng giữ được quan hệ nghiệp vụ. Salting/sharding hot key tăng parallelism nhưng mất sự tuần tự tự nhiên theo entity, cần bước hợp nhất hoặc sequence check. Migration partitioning cần kế hoạch drain/cutover hoặc kiểm soát version, không chỉ bấm tăng partition rồi coi ordering giữ nguyên.
- Production evidence
Bài thử: dùng phân bố key gần production, không chỉ random đều. Đo messages/bytes và lag theo partition, top hot keys bằng dữ liệu đã ẩn danh; chạy thêm tình huống đổi partition count. Tiêu chí: hotspot được định lượng và cùng entity không bị áp dụng sai sequence trong migration.
13.Retention khác delete-on-consume?
Kafka giữ record theo time/size/compaction, độc lập consumer; nhiều group đọc/replay bằng offsets riêng.
- Mental model
Kafka giữ log độc lập với việc một consumer group đã đọc tới đâu. Với delete policy, retention theo thời gian/dung lượng quyết định vòng đời; compaction giữ trạng thái theo key chứ không giữ đầy đủ mọi lịch sử. Group A commit không xóa record cho group B; mỗi group quản lý checkpoint riêng.
- Failure window
Consumer chậm quá retention có thể mất khả năng đọc lại record đã bị xóa; reset offset không khôi phục dữ liệu không còn trong log. Compaction có thể loại các giá trị cũ cùng key, nên một compacted topic không mặc nhiên là audit log đầy đủ. Đọc xong cũng không đồng nghĩa dữ liệu nhạy cảm đã được xóa.
- Trade-off
Retention dài tạo dư địa replay và nhiều consumer độc lập nhưng tốn storage, replication và quản trị privacy. Thiết kế theo thời gian gián đoạn tối đa cộng thời gian catch-up. Chọn delete, compact hoặc kết hợp theo ý nghĩa dữ liệu; snapshot/state topic và event history phục vụ hai mục đích khác nhau.
- Production evidence
Bài thử: dùng hai group, dừng một group, cho group kia tiếp tục rồi replay trong và ngoài retention đã cấu hình. Với compaction, so tập phiên bản còn lại của từng key. Tiêu chí: nhóm vận hành biết earliest offset hiện có, khoảng replay khả dụng và cảnh báo trước khi consumer tụt khỏi cửa sổ đó.
14.Current position khác committed position?
Current là vị trí session tiếp theo; committed là checkpoint recovery sau restart/rebalance.
- Mental model
Current position là offset tiếp theo consumer instance sẽ đọc; committed position là checkpoint dùng khi phục hồi group. Ví dụ poll các record 40–44 có thể đưa position lên 45 trong khi committed vẫn là 40. Cả hai đều không tự xác nhận DB đã áp dụng record 40–44.
- Failure window
Crash sau poll nhưng trước commit làm instance mới đọc lại từ checkpoint đã lưu. Ngược lại, commit 45 khi mới xử lý xong 40 làm recovery bỏ qua công việc 41–44. Khi xử lý bất đồng bộ, position đã tiến không có nghĩa toàn bộ batch đã hoàn thành.
- Trade-off
Theo dõi progress hoàn tất của từng partition, chỉ commit offset kế tiếp của đoạn đã xử lý liên tục, không vượt qua lỗ hổng. Commit thường xuyên giảm lượng replay nhưng tăng overhead; commit theo batch hiệu quả hơn nhưng mở rộng duplicate window. Recovery còn phụ thuộc record/checkpoint vẫn tồn tại và reset policy khi chúng không hợp lệ.
- Production evidence
Bài thử: poll một batch, hoàn tất vài record rồi kill process. Ghi riêng fetched position, committed offset và business-applied IDs. Tiêu chí: sau restart, record chưa hoàn tất vẫn được xử lý; record lặp không nhân đôi effect. Dashboard và log không dùng ba khái niệm này thay thế cho nhau.
15.Commit trước hay sau process?
Trước: at-most-once/loss window. Sau: at-least-once/duplicate window. External side effect cần idempotency.
- Mental model
Đặt checkpoint trước hay sau business processing là chọn vị trí cửa sổ lỗi. Trong flow đơn giản, commit trước process thiên về at-most-once với nguy cơ bỏ sót; process rồi commit thiên về at-least-once với khả năng xử lý lặp. Đây là scope recovery của consumer, không phải lời hứa cho toàn workflow.
- Failure window
Commit thành công rồi crash trước DB commit: consumer mới không tự đọc lại công việc đó. DB commit xong rồi crash trước offset commit: record được đọc lại và có thể apply lần hai. Với batch xử lý lệch thứ tự, commit offset cao nhất đã xong có thể bỏ qua record thấp hơn vẫn thất bại.
- Trade-off
Với công việc cần an toàn, thường xử lý/idempotent-write trước rồi commit checkpoint liên tục. Auto-commit không hiểu completion của executor bất đồng bộ nên phải kiểm soát vòng poll và worker. DB/payment/email bên ngoài không tham gia Kafka offset commit; cần inbox/outbox, idempotency key hoặc protocol phối hợp phù hợp.
- Production evidence
Bài thử: đặt crash point trước DB commit, sau DB commit và sau offset commit. Đối chiếu input IDs, checkpoint và bảng business outcomes. Tiêu chí: mô tả được chính xác cửa sổ loss/duplicate của cách chọn; không ghi “không mất” nếu retention, retries hoặc lỗi vĩnh viễn còn chưa được xử lý.
16.Rebalance gây duplicate thế nào?
Member xử lý nhưng chưa commit trước revoke; member mới đọc lại từ committed offset.
- Mental model
Consumer group chia ownership partition giữa các member; rebalance thay đổi ownership, không chuyển transaction DB đang chạy sang member mới. Nếu member A đã xử lý nhưng chưa commit checkpoint, B được gán partition có thể đọc lại từ committed offset cũ. Group khác vẫn có checkpoint độc lập.
- Failure window
A có thể còn thực thi HTTP/DB request sau khi quyền sở hữu partition đã chuyển cho B. Hai handler cùng tác động một entity, tạo duplicate hoặc race. Broker từ chối commit của member cũ không hủy được side effect đang chạy ở dịch vụ bên ngoài Kafka.
- Trade-off
Khi revoke, dừng nhận thêm việc cho partition đó, drain/cancel có giới hạn và chỉ commit tiến độ hợp lệ khi còn ownership. Idempotency hoặc fencing ở tầng nghiệp vụ vẫn cần cho stale worker. Cooperative assignment/static membership có thể giảm churn trong điều kiện phù hợp, không biến rebalance thành thao tác atomic với DB.
- Production evidence
Bài thử: triển khai rolling update hoặc gây membership churn đúng lúc DB đã commit nhưng offset chưa commit. Ghi member identity/generation, assignment, revoke, offset và event ID. Tiêu chí: stale worker không phá dữ liệu; số duplicate delivery giải thích được; không có business effect trùng dù log xử lý có thể xuất hiện ở hai member.
17.max.poll.interval liên quan gì?
Poll loop quá lâu khiến member bị loại và partitions reassigned dù handler cũ có thể còn chạy.
- Mental model
Tên cấu hình đầy đủ là
max.poll.interval.ms: khoảng tối đa giữa các lần gọi poll khi dùng group management. Nó kiểm soát tiến độ poll, không giống heartbeat/session timeout. Vượt ngưỡng có thể dẫn tới rebalance; với static membership, thời điểm reassignment còn phụ thuộc session timeout và protocol đang dùng.- Failure window
Batch lớn, GC pause hoặc HTTP request treo làm lần poll sau đến muộn. Handler cũ có thể vẫn chạy trong lúc partition chuyển sang member khác, tạo duplicate/race. Tăng heartbeat không tự giải quyết poll loop quá chậm; timeout của Kafka cũng không tự rollback giao dịch ngoài broker.
- Trade-off
Giới hạn thời gian xử lý, giảm
max.poll.records, đặt downstream timeout và đo tail latency trước khi nâng poll interval. Worker pool cần queue hữu hạn, pause/resume hợp lý và completion tracking theo partition; không chia sẻ KafkaConsumer tùy tiện giữa worker threads. Timeout dài giảm false eviction nhưng có thể kéo dài thời gian phát hiện consumer kẹt.- Production evidence
Bài thử: chèn handler chậm hơn poll budget trong lab, có và không có static membership. Thu khoảng cách poll, batch processing p99, rebalances, commit failures và thời gian reassignment. Tiêu chí: biết rõ khi nào ownership đổi, handler cũ xử lý ra sao và cấu hình mới giữ được recovery/SLO chứ không chỉ giấu timeout.
18.acks=all có đủ durability?
Cần replication factor, min.insync.replicas, ISR health và unclean election policy phù hợp.
- Mental model
acks=allliên quan tới xác nhận từ tập in-sync replicas, không có nghĩa mọi replica cấu hình luôn còn sống. Trong mô hình ISR cơ bản, tất cả replica đang ở ISR phải xác nhận;min.insync.replicaslà ngưỡng chấp nhận ghi, không phải số replica cố định chỉ cần chờ. Durability còn phụ thuộc replication factor, ISR health, storage/failure domains và election policy; đây không phải xác nhận consumer đã xử lý.- Failure window
Ví dụ RF=3, min ISR=2 và acks=all: khi ISR xuống dưới ngưỡng, producer có thể gặp lỗi ghi. Khi timeout/lỗi xảy ra, ứng dụng không luôn biết record đã được append hay chưa. Unclean election có thể chọn replica thiếu dữ liệu; mất toàn bộ bản sao tốt vượt khỏi phạm vi chịu lỗi.
- Trade-off
Ngưỡng min ISR cao hơn ưu tiên safety nhưng có thể giảm write availability khi replica mất đồng bộ. Đặt min ISR thấp để hết lỗi có thể giảm độ bền đã hứa. Theo dõi cả effective config và tính năng election như ELR nếu được bật; không sao chép recipe mà bỏ qua phiên bản/protocol thực tế.
- Production evidence
Bài thử: giảm ISR từng bước, gây leader failure và gián đoạn phản hồi produce. Thu ISR membership, under-replicated/under-min-ISR partitions, produce errors, latency và tập ID được xác nhận. Tiêu chí: biết khi nào hệ thống từ chối ghi, unknown outcome được reconcile và không dùng HTTP 200 của producer làm bằng chứng business completion.
19.Idempotent producer giải quyết gì?
Loại duplicate do retry trong producer session và bảo vệ ordering theo supported configuration; không dedupe business events toàn hệ thống.
- Mental model
Idempotent producer dùng producer identity/sequence để chống bản ghi lặp do retry của chính producer trong scope được hỗ trợ. Nó bảo vệ ghi log và ordering với cấu hình phù hợp; không đọc event ID nghiệp vụ để dedupe mọi lần ứng dụng gọi send, cũng không làm consumer hoặc payment API idempotent.
- Failure window
Broker append rồi phản hồi mất: retry nội bộ có thể được nhận diện. Nhưng ứng dụng chủ động send cùng event hai lần hoặc một producer mới phát lại event không mặc nhiên được dedupe theo business ID. Tắt idempotence trong khi có nhiều request in-flight và retry có thể gây reorder.
- Trade-off
Với Kafka Java producer được tham chiếu, kiểm tra
enable.idempotence=true,acks=all, retries>0 vàmax.in.flight.requests.per.connection<=5. Không chỉ dựa vào default vì cấu hình xung đột có thể thay đổi kết quả hoặc gây lỗi. Duy trì stable event ID, outbox và idempotent consumer cho các scope ngoài producer retry.- Production evidence
Bài thử: gây retry do mất phản hồi mạng, rồi tách riêng tình huống ứng dụng gọi send hai lần và restart producer. So số record thực trong partition, thứ tự sequence và business outcomes. Tiêu chí: báo cáo phân biệt transport retry với business duplicate; không tuyên bố “idempotence đã giải quyết mọi duplicate”.
20.Kafka transaction bao phủ đâu?
Atomically Kafka reads/offsets và Kafka writes; DB/payment/email bên ngoài vẫn cần coordination.
- Mental model
Cụm “Kafka reads/offsets” trong đáp án ngắn cần hiểu chính xác: transaction gộp Kafka output records và committed input offsets của consumer group, không rollback việc đã đọc hay mọi lệnh ứng dụng. Scope điển hình là consume–transform–produce trong cùng Kafka cluster; DB/payment/email nằm ngoài atomic boundary này.
- Failure window
Crash trước transaction commit làm output chưa commit không được downstream
read_committednhìn thấy, và input có thể được xử lý lại. Nếu code đã gọi payment trước crash, Kafka abort không hoàn tiền hay xóa side effect đó. Read-uncommitted consumer có thể thấy record từ transaction chưa commit/đã abort.- Trade-off
Dùng transactional producer, identity/fencing phù hợp, đưa offsets vào transaction bằng
sendOffsetsToTransactionvà downstreamisolation.level=read_committed. Không commit offsets riêng song song với transaction. Transactions tăng coordination, latency và yêu cầu xử lý abort/fencing; external side effects cần idempotency/coordination riêng, không “bật EOS” là xong.- Production evidence
Bài thử: kill process sau khi tạo output nhưng trước commit transaction, rồi chạy lại. So committed outputs, input checkpoints và business ledger ngoài Kafka. Tiêu chí: output/checkpoint trong scope Kafka nhất quán sau recovery; bài thử phải chỉ ra external effect vẫn có thể lặp nếu chưa được bảo vệ.
03. Design và operations
Câu 21–30 · 10 câuKết nối broker với business correctness: idempotency, schema, broker selection, retry ordering, observability, scaling, DR và incident response.
21.Idempotent consumer tránh race thế nào?
Unique insert message/business key trong cùng DB transaction với side effect; duplicate vi phạm constraint và không apply lần hai.
- Mental model
Đừng làm “SELECT xem có chưa → nếu chưa thì UPDATE” bằng hai bước không atomic. Dùng unique key cho event/operation trong cùng DB transaction với business mutation: ghi inbox marker, cập nhật dữ liệu, rồi commit. Hai worker tranh cùng key thì chỉ một transaction được phép áp dụng effect tương ứng.
- Failure window
Ghi marker rồi commit riêng trước business update có thể làm mất xử lý khi crash. Update DB rồi mới ghi marker trong transaction khác có thể nhân đôi effect. Transaction DB không bao trùm HTTP payment/email: request có thể thành công nhưng response mất, trong khi marker local chưa phản ánh kết quả.
- Trade-off
Chọn dedupe key đúng scope, ví dụ consumer logic + operation ID, và giữ marker đủ lâu cho retry/replay. Với PostgreSQL có thể dùng insert-on-conflict kèm kiểm tra kết quả insert để quyết định có apply hay không; đừng nuốt mọi DB error thành “duplicate”. Remote side effect cần idempotency key của đích hoặc workflow outbox + reconciliation.
- Production evidence
Bài thử: cho nhiều worker nhận cùng event đồng thời, chèn crash giữa từng bước và replay lại sau restart. Kiểm tra unique conflicts, số mutation đã commit và kết quả phía remote nếu có. Tiêu chí: một effect local cho đúng operation key; cùng ID nhưng payload khác phải bị phát hiện thay vì âm thầm coi là bản sao hợp lệ.
22.Schema change nào thường tương thích?
Add optional field có default; remove/rename/change meaning thường phá reader. Test rolling mixed versions.
- Mental model
Compatibility là quan hệ writer schema ↔ reader schema theo từng chiều, không phải “JSON thì thêm gì cũng được”. Thêm optional field với default hợp lệ thường là hướng an toàn, nhưng còn tùy format và reader. Với Avro, default của reader giúp đọc dữ liệu cũ thiếu field; không có nghĩa writer được tùy ý bỏ field.
- Failure window
Rolling deployment tạo old writer/new reader và new writer/old reader; replay tạo new reader/old historical data. Rename/remove/change meaning có thể phá reader dù payload vẫn parse được. Ví dụ đổi đơn vị từ đồng sang nghìn đồng vẫn cùng numeric type nhưng làm sai nghiệp vụ; schema checker không tự hiểu ý nghĩa đó.
- Trade-off
Chọn backward, forward, full và transitive theo rollout/retention, thay vì mặc định một chế độ đủ cho mọi consumer. Removal/rename đôi khi tương thích với format và chiều đọc cụ thể, không phải luôn luôn an toàn hay luôn luôn hỏng. Cần deprecation window, owner contract và version/schema ID; breaking change có thể cần event type hoặc topic mới.
- Production evidence
Bài thử: chạy ma trận old/new producer–consumer cùng các payload lịch sử còn trong retention; có mẫu thiếu field, null, unknown enum và khác đơn vị. Lưu compatibility check, decode errors/DLQ và assertion business values. Tiêu chí: cả parse và ý nghĩa dữ liệu đều đúng trong các tổ hợp được hỗ trợ.
23.RabbitMQ hay Kafka cho task queue?
RabbitMQ thường tự nhiên khi cần routing, per-message TTL/DLX và work distribution; xác nhận bằng retention/replay/scale requirements.
- Mental model
Task queue thường là mỗi công việc được một worker nhận để xử lý, không phải mọi service đều cần replay toàn lịch sử. RabbitMQ thường tự nhiên với exchange routing, work distribution, manual ack và TTL/DLX. Quyết định vẫn phải xuất phát từ ownership, ordering, retention/replay, throughput, latency và đội ngũ vận hành.
- Failure window
Worker crash sau side effect nhưng trước ack vẫn có thể chạy task lần nữa. Message hết TTL hoặc bị dead-letter không chứng minh business task đã hoàn tất. Một lựa chọn broker phù hợp happy path vẫn có thể thất bại khi retry storm, broker outage hoặc downstream outage xảy ra.
- Trade-off
Chọn RabbitMQ khi routing/task lifecycle là trung tâm; chọn Kafka khi backlog là event log cần nhiều group độc lập và replay. Kafka vẫn làm được nhiều workload task, nhưng offset/retry/ordering phải được thiết kế phù hợp. So sánh ở đây dùng RabbitMQ queues và KafkaConsumer groups thông thường, không khẳng định các mô hình mở rộng khác không tồn tại.
- Production evidence
Bài thử: POC với payload, TLS/auth, durability và burst gần production; kill worker, ngắt downstream và chạy retry/DLQ. Ghi p99 end-to-end age, duplicate/loss reconciliation, replay needs, chi phí và recovery time. Tiêu chí: có decision matrix gắn requirement, không kết luận từ benchmark throughput một chiều.
24.Kafka hay RabbitMQ cho audit stream?
Kafka thường phù hợp retention dài, replay và nhiều independent consumers; cần key, partition, privacy và storage plan.
- Mental model
Audit stream thường cần giữ sự kiện để nhiều consumer đọc độc lập và đọc lại. Kafka phù hợp mô hình partitioned log + retention + checkpoints riêng; vẫn cần quyết định key, số partition, storage budget và privacy. RabbitMQ queues thiên về delivery; RabbitMQ Streams là mô hình khác cần đánh giá riêng khi có yêu cầu tương tự.
- Failure window
Retention quá ngắn, compaction sai mục tiêu hoặc quyền admin quá rộng có thể làm mất lịch sử cần đối chiếu. Producer mất event trước publish cũng tạo lỗ hổng dù log broker vẫn khỏe. Log có retention không mặc nhiên là kho lưu trữ bất biến hoặc chứng cứ chống sửa đổi.
- Trade-off
Dùng event history không compact khi phải giữ mọi biến đổi; cân nhắc archive độc lập có chính sách bảo vệ phù hợp. Tính storage theo ingress bytes, retention, replication và headroom, kèm compression thực tế. PII cần minimization, access control và deletion/lifecycle; yêu cầu audit và yêu cầu xóa dữ liệu phải được thiết kế cùng nhau.
- Production evidence
Bài thử: đối chiếu audit events với nguồn giao dịch, cho nhiều group đọc ở tốc độ khác nhau và rebuild một projection từ khoảng lịch sử đã chọn. Thu missing IDs, replay duration, retained range và quyền truy cập thực tế. Tiêu chí: lịch sử đủ cho mục đích đã nêu, không suy ra tính bất biến chỉ từ việc dùng Kafka.
25.Exactly-once nên trả lời thế nào?
Luôn nêu scope, assumptions và external side effects; không tuyên bố guarantee toàn business workflow.
- Mental model
Bắt đầu bằng câu hỏi: “Một lần” cho record trong broker, output Kafka, hay business effect nào? Exactly-once trong flow consume–transform–produce của Kafka là scope output/checkpoint có coordination phù hợp; không có nghĩa handler chỉ chạy một lần. Với DB local, transaction + unique operation key có thể bảo vệ một mutation theo key trong phạm vi đã thiết kế.
- Failure window
Payment thành công nhưng client mất response là unknown outcome: retry có thể thu tiền hai lần nếu đích không hỗ trợ idempotency đúng cách. Kafka transaction abort không hoàn tác payment. Ngược lại, bỏ retry để tránh trùng có thể để business workflow thiếu bước hoàn tất; cả hai đều cần reconciliation.
- Trade-off
Một câu trả lời senior nên nêu atomic boundary, assumptions về broker/client/storage, cách xử lý retry/crash và external effects. Thường chọn at-least-once delivery + idempotent business processing thay vì hứa end-to-end tuyệt đối. State rõ retention của dedupe marker/key và giới hạn replay; vượt cửa sổ đó phải có quy trình riêng.
- Production evidence
Bài thử: tạo failure matrix cho từng ranh giới publish, receive, DB commit, ack/offset commit và remote response. Với từng case, đối chiếu record count, committed outputs, inbox ledger và business result. Tiêu chí: mọi tuyên bố “exactly-once” đều kèm scope, điều kiện và evidence; không dùng một con số duplicate bằng 0 trong happy path làm chứng minh tổng quát.
26.Retry topic có thể phá ordering?
Message lỗi rời main partition trong khi message sau tiếp tục; cần per-key block, state machine hoặc chấp nhận reorder có chủ đích.
- Mental model
Giả sử event A1 lỗi được chuyển sang retry topic, còn A2 cùng key tiếp tục ở main topic. Thứ tự vẫn đúng trong mỗi log nhưng business apply order có thể thành A2 → A1. Giữ cùng key ở retry topic không tạo total order giữa main và retry topics.
- Failure window
Ngoài reorder, còn cửa sổ bàn giao: publish retry thành công rồi crash trước commit offset gốc tạo lặp; commit gốc trước khi retry publish bền vững tạo mất công việc. Kafka transaction có thể gộp retry record và offset gốc trong cùng cluster, với consumer isolation phù hợp; nó không kéo external side effects vào transaction.
- Trade-off
Có thể pause partition để giữ thứ tự nhưng một poison event chặn cả các key khác. Per-key block/buffer cho throughput tốt hơn nhưng cần durable state, capacity bound và recovery. State machine/entity-version check giúp xử lý reorder có chủ đích; phải định nghĩa cách xử lý event thiếu, đến muộn hoặc không thể retry tiếp.
- Production evidence
Bài thử: gửi A1, A2 cùng key và B1 khác key, buộc A1 lỗi; sau đó replay và gây crash lúc chuyển retry. Thu timeline main/retry, offsets và business entity versions. Tiêu chí: bảo toàn invariant đã chọn hoặc chứng minh reorder được xử lý hợp lệ; không chỉ kiểm tra mọi message cuối cùng đều được nhận.
27.Lag bằng 0 có nghĩa healthy?
Không; có thể commit trước process hoặc handler silently fail. Cần processing success/age và side-effect metrics.
- Mental model
Lag phản ánh khoảng cách offset theo định nghĩa của metric/dashboard, không phải số business transaction thành công. Committed lag bằng 0 có thể đi cùng commit sớm, handler nuốt lỗi hoặc công việc còn nằm trong local executor. Fetch-position lag và committed lag cũng không nên bị gọi chung mà thiếu nhãn.
- Failure window
Consumer bắt exception rồi vẫn commit làm record không tự replay trong khi nghiệp vụ chưa chạy. Producer ngừng phát event có thể khiến cả hệ thống lag bằng 0 nhưng pipeline thực tế đã chết. Retry/DLQ hoặc transaction chưa hoàn tất cũng có thể giấu công việc khỏi panel đang xem.
- Trade-off
Dùng nhiều lớp tín hiệu: ingress expected/actual, completion rate, end-to-end processing age, retry/DLQ age và downstream outcomes. Chọn SLO dựa trên điều người dùng nhận được. Timestamp phải có ngữ nghĩa rõ; đồng hồ lệch hoặc event tạo từ lâu có thể làm phép đo age gây hiểu lầm.
- Production evidence
Bài thử: cố ý commit trước process, cho handler silently fail và tạm dừng producer trong ba kịch bản riêng. Gửi synthetic canary có expected business outcome. Tiêu chí: alert phát hiện pipeline lỗi dù lag bằng 0, và trace chỉ ra record dừng ở bước nào chứ không chỉ báo consumer vẫn poll.
28.Scale consumer khi nào không hiệu quả?
Kafka khi members vượt partitions; cả hai khi downstream/DB là bottleneck hoặc hot key/queue không chia được.
- Mental model
Với KafkaConsumer group theo mô hình gán partition độc quyền, số member xử lý tích cực bị giới hạn bởi số partition được gán; thêm member vượt giới hạn không tạo thêm parallelism đọc. Quy tắc này không áp dụng nguyên xi cho share groups. Cả RabbitMQ và Kafka đều có thể bị giới hạn bởi DB, API, hot key hoặc một queue/partition.
- Failure window
Scale-out khi DB đã bão hòa có thể tăng connection contention, timeout, retries rồi tạo thêm duplicate. Kafka deployment đồng loạt còn có thể gây rebalance churn. Với RabbitMQ, consumer nhiều hơn không chữa được single-queue bottleneck hoặc ordering requirement khiến công việc phải tuần tự.
- Trade-off
Đo bottleneck trước khi scale. Tăng partition/queue shards có thể mở parallelism nhưng đổi key distribution, ordering, metadata và chi phí vận hành. Tune concurrency/prefetch/batching cùng giới hạn downstream; đặt capacity headroom và autoscaling guardrails. Không lấy CPU consumer thấp làm bằng chứng broker hoặc DB không nghẽn.
- Production evidence
Bài thử: giữ workload cố định, tăng consumer theo từng mức và quan sát throughput, p99 age, DB wait/connection pool, broker IO, skew và rebalances. Tiêu chí: xác định điểm tăng thêm worker không tạo lợi ích hoặc làm SLO xấu đi; quyết định shard hay giảm tải dựa trên dữ liệu đó.
29.Broker replication có thay backup?
Không; replication sao chép deletion/corruption và thường cùng failure domain. Backup/DR giải quyết retention và disaster khác.
- Mental model
Replication bảo vệ availability/durability trước một số lỗi replica; backup/DR phục vụ khôi phục theo thời điểm hoặc sau thảm họa. Ý “corruption” ở đáp án ngắn nên hiểu là dữ liệu sai logic hay thao tác phá hủy có thể lan sang bản sao, không phải mọi lỗi bit trên một disk đều được copy nguyên xi. Failure domains thực tế phụ thuộc placement.
- Failure window
Xóa nhầm topic/queue, ứng dụng ghi dữ liệu sai hoặc mất cả vùng có thể vượt khỏi replication local. Mirror/standby cũng không mặc nhiên có lịch sử point-in-time độc lập. Với RabbitMQ, export definitions chỉ lưu topology/metadata, không phải backup message payload; copy dữ liệu sống tùy tiện còn có nguy cơ snapshot không nhất quán.
- Trade-off
Xác định RPO, RTO, retention, quyền xóa và nơi giữ bản phục hồi độc lập. DR phải gồm data, topology/topic config, schemas, ACLs và checkpoints phù hợp. Khôi phục offset cũ có thể replay side effect; khôi phục offset mới hơn dữ liệu business có thể bỏ việc. Đừng lấy “có replica thứ hai” thay cho runbook restore.
- Production evidence
Bài thử: restore vào môi trường cô lập theo phương án hỗ trợ của phiên bản đang chạy, đo RPO/RTO thực và đối chiếu ID/checksum nghiệp vụ. Kiểm tra schema, permissions, replay và failback, không chỉ broker khởi động. Tiêu chí: có biên bản restore thành công và các khoảng dữ liệu không thể phục hồi được nêu rõ.
30.Debug incident duplicate hàng loạt?
Xem deploy/rebalance/connection recovery, commit/ack timing, retry, idempotency constraint, trace theo message ID và downstream outcome.
- Mental model
Tách duplicate publish, duplicate delivery và duplicate business effect. Cùng event ID xuất hiện hai lần trong log handler chưa chứng minh DB bị cập nhật hai lần. Bắt đầu từ timeline deploy/rebalance/connection recovery, ack/commit timing, retry topology và idempotency constraint rồi nối với outcome phía downstream.
- Failure window
DB đã commit trước khi connection đứt gây redelivery; publish chưa rõ confirm có thể bị relay phát lại; replay tool có thể tạo business event mới với ID khác. Rebalance để stale handler tiếp tục chạy và marker dedupe hết retention cũng là cửa sổ cần kiểm tra. Đừng kết luận “broker gửi trùng” chỉ vì mọi lỗi xảy ra cùng lúc.
- Trade-off
Ưu tiên dừng amplification: pause replay không kiểm soát, giới hạn retry/ingress và bảo vệ downstream. Không purge queue, reset offsets hoặc đổi sang auto-ack chỉ để làm số duplicate giảm. Thu evidence trước, sửa timing/idempotency/ownership theo nguyên nhân, rồi canary và reconcile những operation có kết quả chưa rõ.
- Production evidence
Bài thử/runbook: lấy mẫu theo event ID + business key, đối chiếu publish attempts, Rabbit channel/tag/redelivered hoặc Kafka topic/partition/offset/member, DB constraint và remote outcome. Tiêu chí: phân loại được nguyên nhân, định lượng effect trùng thật, chứng minh bản sửa qua crash test và replay có kiểm soát; lưu rõ phần chưa đủ bằng chứng.