GH GambleHub

Outbox үлгүсү

Outbox - бул архитектуралык үлгү, анда домендик кызмат өзүнүн кампасында бир жергиликтүү транзакцияда бизнес өзгөрүшүн жана тиешелүү окуяны жазат. Окуяны тышкы шинага/кезекке жарыялоо "outbox" таблицасын окуган жана жазууларды ретрансляциялаган өзүнчө коопсуз процесс (publisher) менен синхрондуу аткарылат. Бул ыкма жарыш жок "биринчи DD, андан кийин дөңгөлөк", ал тургай, ийгиликсиз учурда ишенимдүү жеткирүүнү камсыз кылат.

1) Качан колдонуу керек

Ылайыктуу:
  • Микросервистер жана контексттердин ортосундагы окуялар менен модулдук монолиттер.
  • Бул кепилдик талап кылынат, "абалы жазылган окуя жоголуп кетиши мүмкүн эмес".
  • Демпотенттик жана контролдук кайра жеткирүү керек.
Туура эмес:
  • Бир нече ресурстарда катуу глобалдык транзакциялар маанилүү (так келишимдер менен TSS/сагадан жакшыраак).
  • Эч кандай атайын чындык булагы (мамлекет окуя түзүлгөн жерде сакталган эмес).

2) Максаттары жана касиеттери

Atomic write: домен жазуусу + outbox - бир бүтүмүндө.
At-least-once жарыялоо: кайталап жол, жоготуу жок.
Керектөөчүлөрдүн демпотенттүүлүгү: абоненттер тарапта дубльдан коргоо.
Натыйжалуу exactly-once: outbox + idempotent consumer + dedup айкалышы менен жетишилет.
Так телеметрия: бизнес-иш-чаралар менен байланыш.

3) Маалыматтар схемасы (мисал)

sql
-- Domain table (example: orders)
CREATE TABLE orders (
id       UUID PRIMARY KEY,
tenant_id    TEXT NOT NULL,
status     TEXT NOT NULL,
total_amount  NUMERIC(12,2) NOT NULL,
updated_at   TIMESTAMP NOT NULL DEFAULT now()
);

-- Outbox
CREATE TABLE outbox (
id       UUID PRIMARY KEY,        -- event_id aggregate_type TEXT NOT NULL,          -- 'order'
aggregate_id  UUID NOT NULL,          -- order_id tenant_id    TEXT NOT NULL,
type      TEXT NOT NULL,          -- 'OrderCreated'
payload JSONB NOT NULL, -- serialized headers event JSONB NOT NULL DEFAULT '{}':: jsonb,
occurred_at TIMESTAMP NOT NULL, -- time in domain transaction available_at TIMESTAMP NOT NULL, -- earliest publish time (backoff)
published_at TIMESTAMP, - is filled by the attempts INT NOT NULL DEFAULT 0,
error      TEXT
);

CREATE INDEX ON outbox (available_at) WHERE published_at IS NULL;
CREATE INDEX ON outbox (tenant_id, available_at) WHERE published_at IS NULL;

4) Транзакциялык шаблон (application layer)

pseudo begin tx domainChange () # INSERT/UPDATE in domain table insert into outbox (event) # event with aggregate/tenant commit tx keys

Эгерде коммит ийгиликтүү болсо - outbox окуясы бар деп кепилдик берилет. Эгерде тиркеме коммиттен кийин куласа, анда коомчулук аны кууп жетет.

5) Publisher (reader → publisher)

Милдеттери:
  • Мезгил-мезгили менен жарыяланбаган окуяларды ('published _ at IS NULL' жана 'available _ at <= now ()'), батч.
  • шиналар/кезек жарыялоого аракет; ийгиликтүү болсо, 'published _ at' деп белгилөө керек.
  • ката - көбөйтүү 'attempts', келечекке 'available _ at' коюп (exponential backoff), 'error' жазуу.
  • Тенанттар/ачкычтар боюнча лимиттерди урматтоо (fairness), продуктивдүү тоскоолдук кылбоо.
Псевдокод:
pseudo loop:
events = select from outbox where published_at is null and available_at <= now()
order by occurred_at limit BATCH_SIZE for update skip locked

for e in events:
try:
broker. publish(topicFor(e), serialize(e. payload), headers(e))
markPublished(e. id, now())
except Retryable:
backoff = computeBackoff(e. attempts)
reschedule(e. id, now()+backoff, attempts+1, last_error)
except NonRetryable:
moveToDLQ (e) or markError (e) # by sleep (POLL_INTERVAL) policy
💡 'FOR UPDATE SKIP LOCKED' коомдук атаандаштыкты жокко чыгарат.

6) Демпотенттүүлүк жана дедупликация

Керектөөчү тарапта (Inbox/Idempotency store):
sql
CREATE TABLE inbox (
consumer_name  TEXT,
event_id    UUID,
processed_at  TIMESTAMP NOT NULL,
PRIMARY KEY (consumer_name, event_id)
);

Алгоритм: окуяны алганда - биринчи аракет 'INSERT' in 'inbox'; эгерде ачкыч чыр-чатак - окуя буга чейин иштелип чыккан → "no-op". Андан ары - бизнес-логика.

коомдук тарапта: 'Idempotency-Key' жылы headers (мисалы, 'event _ id'), ошондуктан шиналар/брокер/прокси дубликаттарын чыпкалап алат.

7) Тартиби жана себептери

'aggregate _ id' боюнча жергиликтүү тартип 'occurred _ at' сорттоо жана 'ачкыч боюнча' жарыялоо менен камсыз кылынат.
Партиялаштыруу менен лог-шиналар үчүн - бир агрегаттын окуялары бир партишенде болушу үчүн 'aggregate _ id '/' tenant _ id' ачкычы менен партиялаңыз.
Эгерде тартип оор болсо, бир ачкыч боюнча эл аралык жарыштан качыңыз.

8) CDC (Change Data Capture)

Активдүү жарнаманын ордуна CDC колдонсо болот: кыймылдаткыч DD транзакцияларынын журналын окуйт жана 'outbox' саптары шинага которулат. Плюсы - минималдуу жүк DD, так ырааттуулугу, жок polling. Кемчиликтери - операцияны татаалдаштыруу жана СУБДнын өзгөчөлүгүнө байлоо. Эки ыкма тең валиддик; компетенттүүлүк жана SLO боюнча тандоо.

9) Каталар, DLQ жана Редрайв

Retryable (тармак, лимиттер) - көбөйтүү 'attempts', кийинкиге калтыруу 'available _ at' (exponential backoff + життер).
Non-retryable (нөлдүк схема/келишим) - DLQ/Dead-Letter Topic бай метадеректер менен которулат.
Коопсуз редрайв: батчи, rate-limit, схема валидациясы, прод-трафиктен төмөн артыкчылык.

10) Көп-тенанттуулук жана лимиттер

Милдеттүү tags: 'tenant _ id', 'plan', 'region' - 'outbox'. headers`.
Per-tenant fairness: pablisher бөлүштүрөт "терезе" жарыялоо жана лимиттери аракет ижарачылар.
Residency: домендик маалыматтар бир аймакта outbox сактоо; аймактар аралык жарыялоо - агрегаттар/отчеттор гана.

11) Коопсуздук жана шайкештик

PII-өзгөртүүлөр жана толуктоолор менен payload/башчысы tenant/аймак саясаты боюнча.
Кол коюу/шина "бөтөн" болсо, пайдалуу жүктү шифрлөө.
Бардык мамлекеттик өткөөл аудити: түзүлгөн, жарыяланган, ката, редрайв.

12) Байкоо

Метрикасы:
  • Жарыяланган лаг ('now - occurred_at' p50/p95/p99).
  • Ийгиликтин үлүшү, каталардын үлүшү, себептердин бөлүштүрүлүшү.
  • outbox көлөмү (жарыяланбаган саны), аракет/сек.
  • throughput жана lag.
Трейсинг:
  • 'event _ id '/' aggregate _ id '/' saga _ id' корреляциясы; "db-tx", "publish", "retry".
  • Түшүндүрмөлөр: 'attempt', 'backoff _ ms', 'dlq = true'.
Логи:
  • Ийгиликке кыскача жазуулар; ката/redrave толук маалымат.

13) сыноо жана башаламандык

Atomicity сыноо: жарыяланганга чейин домендик транзакция коммитинен кийин жасалма "жыгылып" - окуя кийинчерээк чыгып кетүүгө милдеттүү.
Duplicate сыноо: бир эле иш-чараны бир нече жолу жарыялайбыз - консьмер так бир эффектти (inbox) аткарат.
Order сыноо: бир агрегат боюнча окуялардын пакети - ырааттуулугун/ыктымалдыгын текшерүү.
Chaos: брокердин баш тартуусу, БДнын латенттүүлүгүнүн өсүшү, коомчулуктун бөлүнүшү, clock-skew.

14) Конфигурациялык үлгүлөр (мисал)

yaml outbox:
poll_interval_ms: 200 batch_size: 200 order_by: occurred_at backoff:
strategy: exponential_full_jitter initial_ms: 250 max_ms: 10_000 max_attempts: 20 fairness:
per_tenant_parallelism: 4 per_key_serial: true

publisher:
rate_limit_per_sec: 500 headers:
idempotency_key: event_id schema_version: v3 dlq:
enabled: true topic: myapp. events. dlq include_metadata:
- error
- attempts
- source_table
- tenant_id
- aggregate_id

15) Дастан жана Retrains менен бириктирүү

Outbox - саганын кадамдар үчүн "коопсуздук транспорт": жергиликтүү бүтүм таасир жана команда/окуя жазат; жарыялоо - ишенимдүү жана дозалануучу.
Кайталоо жана backoff саясаты 'Retry-After' жана Circuit Breaker менен макулдашылышы керек; "retrais бороонунан" качыңыз.

16) типтүү каталар

Домендик абалдын коммитинен кийинки окуяны жазыңыз - жыгылганда жоготуу болушу мүмкүн.
Эч кандай индекстер/архив 'outbox' → жарыялоо кечигүү өсүшү.
Publisher жок 'SKIP LOCKED' же эч кандай шардана - атаандаштык жана бөгөт коюу.
Керектөөчүлөрдүн демпотенттигинин жоктугу - дубль жана терс таасирлери.
аралаштыруу PII DLQ/Логтордо жашыруу жок.
fairness жок жарыялоо бир дүйнөлүк кезек - "ызы-чуу" Тенант ар бир тоскоолдук кылат.
Жок мониторинг Лаги → жашыруун бузулуулар.

17) Тез тандоо стратегиясы

Старттык деңгээл: DDдан поллинг, 100-500 батчи, full-jitter backoff, консумерлерде inbox.
Жогорку жүк: CDC бүтүм журналынан, 'tenant _ id/aggregate _ id' боюнча шардана, ижарачылар үчүн WFQ.
Агрегаттын катуу тартиби: сериялык жарыялоо per key (mutex), топикти ачкыч менен партиялаштыруу.
Комплаенс/PII: шифрлөө payload, DLQ редакторлору, аймактык outbox.

18) Азык-түлүктүн алдындагы чек-тизме

  • Домендик өзгөрүүлөр жана 'outbox' жазуусу бир транзакцияда болот.
  • Publisher батчи иштетет, 'SKIP LOCKED', Jitter менен backoff жана лимиттерди колдонот.
  • Consumers idempotent (таблица 'inbox '/дедуп журналы).
  • орнотулган DLQ жана коопсуз redrave.
  • P95/P99 босогосунда боюнча Лага/ката жана Алерта өлчөмдөрү.
  • Ачкыч тартиби кепилденген (партия/сериясы).
  • Archive/retenshn 'outbox' жана жарыяланган жазууларды тазалоо.
  • PII-саясат жана мамлекеттик өтүү аудит.
  • Committee жана жарыялоо, кайталоо жана тартиби ортосунда кулап тесттер.
  • Иш-чаранын келишимдеринин документтери (схемалар/версиялар/шайкештик).

Корутунду

Outbox-үлгү "алсыз" байламта "БД шина" ишенимдүү конвейер айлантат: атомдук абалын бекитүү, кепилденген (жок дегенде "бир жолу" болсо да) жарыялоо, демпотенттик абоненттер жана көзөмөлгө алынган редрайв. Туура телеметрия менен, чеги жана тартиби схемалар, ал практикалык exactly-once жүрүм-турумун берет, бөлүштүрүлгөн бүтүмдөрдүн татаалдыгын азайтуу жана каталар жана жогорку жүктөр үчүн системанын туруктуулугун жогорулатуу.

Contact

Биз менен байланышыңыз

Кандай гана суроо же колдоо керек болбосун — бизге кайрылыңыз.Биз дайым жардам берүүгө даярбыз!

Telegram
@Gamble_GC
Интеграцияны баштоо

Email — милдеттүү. Telegram же WhatsApp — каалооңузга жараша.

Атыңыз милдеттүү эмес
Email милдеттүү эмес
Тема милдеттүү эмес
Билдирүү милдеттүү эмес
Telegram милдеттүү эмес
@
Эгер Telegram көрсөтсөңүз — Emailден тышкары ошол жактан да жооп беребиз.
WhatsApp милдеттүү эмес
Формат: өлкөнүн коду жана номер (мисалы, +996XXXXXXXXX).

Түшүрүү баскычын басуу менен сиз маалыматтарыңыздын иштетилишине макул болосуз.