ساعت دو سرور همیشه دقیقاً یکی نیست. NTP آنها را نزدیک میکند، اما ممکن است یکی چند ثانیه جلو باشد یا VM برای مدتی pause شود. پس نباید ساده فرض کنیم «timestamp بزرگتر یعنی اتفاق جدیدتر»؛ این فرض در سیستم توزیعشده گاهی غلط است.
Physical clock
زمان دیواری؛ برای UX و expiry مفید، اما ترتیب علّی را تضمین نمیکند.
Lamport clock
شمارنده منطقی که اگر A قبل از B رخ دهد، L(A)<L(B) است؛ همزمانی را تشخیص نمیدهد.
Vector clock
برای هر replica یک بردار؛ میفهمد دو تغییر مستقل و متعارضاند، اما با تعداد replica بزرگ میشود.
HLC
Hybrid Logical Clock؛ زمان فیزیکی را با شمارنده منطقی ترکیب میکند و برای ترتیب تقریباً واقعی مناسب است.
Snowflake ID
شناسه ۶۴بیتی معمولاً شامل time + worker + sequence؛ مرتب و تولیدش محلی است، ولی باید rollback ساعت و overflow را مدیریت کرد.
ترتیب، deduplication و idempotency
- هر رویداد یک event_id پایدار دارد؛ consumer جدول/کش processed-event نگه میدارد یا upsert شرطی میزند.
- ترتیب Kafka فقط داخل یک partition تضمین است؛ entity_id را key کن و برای رویدادهای out-of-order نسخه/sequence per-entity بگذار.
- «دقیقاً یکبار» انتهابهانتها معمولاً ادعای ترکیبی است: broker transaction + idempotent producer + sink idempotent. در طراحی عمومی، at-least-once را فرض کن.
به زبان ساده
ساعت سرورها دقیقاً همزمان نیست، پس برای ترتیب و یکتایی از شمارندههای منطقی و شناسههای خاص استفاده میکنیم، نه timestamp خام.
مثال واقعی
بانک ممکن است نتیجه پرداخت را بهخاطر قطعی شبکه دوبار بفرستد؛ فروشگاه با دیدن همان event_id برای بار دوم میگوید «قبلاً انجام شده» و پولی دوباره ثبت نمیشود.