Access Hub Collector
Đồng bộ từ mã nguồn lúc 10:57, 03/10/2026
Skip to content
Quan hệ với ADR khác
  1. 0009 Trừu tượng hóa Bus, phân shard...Thay một phần 0012
  2. 0012 Bus Redis Streams, outbox dùng...Đang xem
ADR 0012Chấp nhận

ADR 0012: Bus Redis Streams, outbox dùng chung trong Redis và lease bộ gửi ​

Dùng Redis Streams làm bus giữa ingest và worker, đặt outbox sự kiện trong Redis và điều phối bộ gửi bằng lease Redis, thay cho bus in-process và kế hoạch NATS JetStream ở giai đoạn này.

Ngày quyết định
30/09/2026
Chấp nhận
01/10/2026
Phạm vi
Collector
Người chấp nhận
Product Owner
  1. Đề xuất30/09/2026
  2. Chấp nhận01/10/2026, Product Owner chấp nhận

1. Tiêu đề quyết định (Title) ​

Dùng Redis Streams làm bus giữa ingest và worker, đặt outbox sự kiện trong Redis và điều phối bộ gửi bằng lease Redis, thay cho bus in-process và kế hoạch NATS JetStream ở giai đoạn này.

2. Trạng thái (Status) ​

Chấp nhận (Accepted) ngày 01/10/2026 bởi Product Owner. Ghi nhận một quyết định đã thực hiện trong mã (COL-R). Chấp nhận với điều kiện đã biết: Redis ở dev chỉ để phát triển, chưa có Sentinel hoặc Cluster, nên độ bền của bus, outbox và lease bằng độ bền của một Redis (xem ADR 0013, docs/08).

Một phần thay thế ADR 0009 (ADR 0009 vẫn giữ nguyên interface Bus và 64 shard; phần "GĐ 3 dùng NATS JetStream" và nhận định "Redis Streams không chọn" không còn khớp mã hiện tại).

Một phần thay thế ADR 0009 (ADR 0009 vẫn giữ nguyên interface Bus và 64 shard; phần "GĐ 3 dùng NATS JetStream" và nhận định "Redis Streams không chọn" không còn khớp mã hiện tại).

Ngày quyết định: 30/09/2026 (ngày ghi nhận đề xuất; ngày cài đặt thực tế xem lịch sử git, commit COL-R).

3. Ngữ cảnh (Context) ​

  • ADR 0009 định nghĩa interface Bus với inproc ở giai đoạn 1 và JetStream ở giai đoạn 3, và ghi Redis Streams đã cân nhắc, không chọn vì khó bảo đảm bền vững khi mất Redis.
  • Ngày 30/09/2026 tác vụ COL-R tách tiến trình ingest, worker, admin để chạy riêng. Yêu cầu của người dùng: môi trường dev phải mô phỏng đầy đủ như sản xuất, không làm tạm (xem ADR 0013).
  • Redis đã là phụ thuộc bắt buộc của hệ thống (registry, presence, giới hạn tốc độ), nên dùng thêm cho bus không thêm thành phần vận hành mới. JetStream chưa được cài đặt.
  • Ràng buộc: NFR-07 (đệm khi mất TSDB), NFR-08 (outbox 24 giờ), R9 (ít thành phần).

4. Quyết định (Decision) ​

Cho giai đoạn 1 đến 2, thay vì inproc rồi JetStream:

  1. Bus: Redis Streams, một stream mỗi shard logic (bus:s:<shard>, 64 shard, hash(server_id) mod 64), một consumer group workers. Bản ghi bị xóa sau khi handler xong, nên độ dài stream là backlog. Tiến trình chết giữa chừng để lại bản ghi chưa xác nhận, tiến trình khác nhận lại bằng XAUTOCLAIM sau claim_idle (mặc định 30 giây). Ngữ nghĩa giao hàng: ít nhất một lần, trùng lặp vô hại vì mẫu idempotent theo timestamp. Khi backlog vượt queue_per_shard, ingest trả 503 (ErrFull) và agent giữ đệm.
  2. Outbox sự kiện: dùng chung trong Redis (ob:q zset theo thời gian, ob:e hash sự kiện, ob:dead hash sự kiện chết) để mọi tiến trình đều đưa vào, một tiến trình gửi.
  3. Lease bộ gửi: khóa outbox:sender (SET NX PX, TTL 15 giây, gia hạn, trả lại khi tắt êm) bảo đảm một bộ gửi tại một thời điểm. Lease không có fencing, chỉ bảo vệ công việc an toàn khi chạy hai lần (gửi idempotent theo seq).
  4. Phạm vi: Collector, các vai trò ingest, worker. Interface Bus giữ nguyên để có thể thay bằng JetStream sau này.

5. Cơ sở lý luận (Rationale) ​

Ưu điểm:

  • Không thêm thành phần: Redis đã bắt buộc, giảm tăng độ phức tạp (R9).
  • Cho phép tách ingest và worker chạy ở nhiều tiến trình ngay bây giờ, đúng yêu cầu mô phỏng sản xuất.
  • Có kiểm thử với Redis thật (internal/bus/redis_test.go, internal/outbox/redis_test.go).

Nhược điểm chấp nhận được (cần ghi rõ):

  • Độ bền bus và outbox bằng độ bền của Redis. Cần AOF appendfsync everysec tối thiểu và replica (docs/07); mất tối đa khoảng 1 giây ghi khi Redis sập, và Redis mất hẳn thì mất backlog. Đây chính là lý do ADR 0009 không chọn Redis Streams.
  • Khoảng 500 ms mẫu đang gộp ở worker có thể mất khi worker sập.
  • Redis dùng chính sách noeviction, Redis đầy làm ingest lỗi thay vì âm thầm bỏ dữ liệu.
  • Lease không fencing: trong cửa sổ TTL có thể có hai bộ gửi (hai lần gửi, không mất dữ liệu nhờ idempotent).
  • Mã hiện thực không dùng lease Redis để gán shard cho worker như ADR 0009 mô tả; chia việc bằng consumer group, XAUTOCLAIM xử lý worker chết. Việc trạng thái đánh giá luật vẫn nằm trong bộ nhớ một worker cần được xác nhận ở L2 Collector (chưa kiểm chứng trong phạm vi báo cáo này).

Phương án đã xem xét: xem mục 7.

6. Ảnh hưởng (Consequences) ​

  • Tích cực: chạy được nhiều tiến trình sau cân tải, mô phỏng sản xuất ở dev, backlog quan sát được qua ahc_*.
  • Rủi ro: Redis trở thành điểm lỗi đơn cho bus và outbox nếu không có replica và AOF. Sentinel hoặc Cluster chưa có ở dev (docs/09).
  • Việc tiếp theo:
    • Cập nhật ADR 0009 sang trạng thái "Một phần bị thay thế bởi ADR 0012" khi ADR này được chấp nhận (không sửa trong đợt này vì thuộc sở hữu tài liệu khác).
    • docs/04 mục ghi "Bus in-process ... tách vai trò cần adapter JetStream (chưa làm)" đã lạc hậu so với mã, cần cập nhật.
    • Quyết định giữ Redis Streams hay chuyển JetStream ở giai đoạn 3 dựa trên kiểm thử hỗn loạn (X-9: mất Redis, TSDB, node).
    • Kiểm thử mất Redis giữa chừng với AOF bật.

7. Các phương án được đánh giá (Considered Options) ​

Phương ánƯu điểmNhược điểmKết luận
Bus inproc (ADR 0009 giai đoạn 1)Đơn giản, nhanhKhông tách tiến trình, không bền, không mô phỏng sản xuấtKhông chọn cho dev đầy đủ, vẫn còn ở dạng cấu hình một tiến trình
NATS JetStream (ADR 0009 giai đoạn 3)Lưu tệp, nhân bản, consumer bềnThêm một thành phần vận hành, chưa cài đặtHoãn, xem lại ở giai đoạn 3
Redis StreamsKhông thêm thành phần, tách tiến trình đượcĐộ bền phụ thuộc AOF và replica của RedisChọn (đề xuất)
KafkaMạnh, bềnNặng vận hành (ADR 0009)Không chọn
  • L2: L2 Collector (đang được viết), L1 HLD
  • ADR: 0009, 0008, 0013
  • Tài liệu: docs/04-data-model.md, docs/08-scaling-ha.md, docs/07-security.md, docs/11-roadmap.md (COL-R)
  • Mã: internal/bus/redis.go, internal/outbox/redis.go, internal/outbox/sender.go, internal/redisx/lease.go
  • Rủi ro: R9, R15

9. Phê duyệt (Approvals) ​

TênVai tròGhi chú
chưa chỉ địnhEnterprise ArchitectChưa duyệt
chưa chỉ địnhSolution ArchitectChưa duyệt
Thiện Phan NgọcProduct OwnerChấp nhận 01/10/2026. Redis dev chưa có replica HA, chấp nhận
Trang này có giúp được bạn không?
Sửa trang này

Nội dung đồng bộ từ kho mã access-hub-collector lúc 10:57, 03/10/2026. Khi tài liệu và mã khác nhau, mã thắng.