Double booking ছাড়া ticket booking সিস্টেম ডিজাইন
একই সিট দুজন কিনতে পারবে না। Booking সিস্টেমের জন্য seat hold, locking ও payment timeout ডিজাইন করি।

লক্ষ্য: user শো বা ফ্লাইটের সিট বাছে, অল্প সময় hold করে রাখে, টাকা দেয় ও টিকিট পায়। একটি সিট সর্বোচ্চ একবার বিক্রি হয়।
Requirement
- ইভেন্ট দেখা ও কোন সিট ফাঁকা তা জানা।
- সিট বাছা এবং payment-এর সময় (যেমন ১০ মিনিট) সেগুলো hold রাখা।
- হাজারো মানুষ একসাথে ক্লিক করলেও একটি সিট দুবার বিক্রি হবে না।
- Payment ব্যর্থ বা সময় শেষ হলে সিট ছেড়ে দেওয়া।
কঠিন অংশ: contention
জনপ্রিয় ইভেন্টে অনেকে একই মুহূর্তে একই সিট চায়। সঠিকতা সবার আগে, তাই সিটের অবস্থা atomic ভাবে বদলাতে হবে।
সিটের অবস্থা
AVAILABLE -> HELD (সময় T পর্যন্ত) -> SOLD, আর hold-এর মেয়াদ শেষ বা payment ব্যর্থ হলে HELD -> AVAILABLE।
Double booking ঠেকানো
একটি নিরাপদ পদ্ধতি বাছুন:
- Conditional update:
UPDATE seats SET status='HELD', held_by=?, hold_until=? WHERE seat_id=? AND (status='AVAILABLE' OR hold_until < now())। এক row বদলালে সিট পেয়েছেন। শূন্য হলে অন্য কেউ পেয়েছে। এক statement-এই সহজ ও সঠিক। - Optimistic locking:
versioncolumn রাখুন এবং version মিললে তবেই আপডেট করুন। - Row lock (
SELECT ... FOR UPDATE): নিরাপদ, কিন্তু lock বেশিক্ষণ ধরে। - Hold-এর জন্য Redis
SET key NX EX, আর database চূড়ান্ত সত্যের উৎস।
tickets table-এ (event_id, seat_id)-র unique constraint শেষ নিরাপত্তা জাল।
Booking প্রবাহ
- User সিট বাছে। Server সবগুলো এক transaction-এ hold করতে চেষ্টা করে (সব, নয়তো কিছুই না)।
- User hold-এর সময়ের মধ্যে টাকা দেয়।
- Payment সফল: সিট
SOLDকরে টিকিট তৈরি। এই ধাপ idempotent, তাই retry হওয়া callback দুবার কিছু করে না। - ব্যর্থতা বা timeout: background job (বা lazy মেয়াদ যাচাই) সিট ছেড়ে দেয়।
Payment race
Hold-এর মেয়াদ শেষের ঠিক পরে payment সফল হতে পারে। সফল হলে একই transaction-এ hold আবার যাচাই করুন। সিট চলে গেলে স্বয়ংক্রিয় refund দিন ও user-কে জানান।
ভিড় সামলানো
- Virtual waiting room: user-দের ভাগে ভাগে ঢোকান যাতে booking পথ ডুবে না যায়।
- সিট মানচিত্র cache থেকে দিন, আর hold-এর সময় উপলব্ধতা যাচাই করুন।
- Rate limit দিন ও bot আটকান।
- Read অনায়াসে scale করুন, কিন্তু সিট table-এ write পথ ছোট ও দ্রুত রাখুন।
Scaling
ইভেন্ট অনুযায়ী shard করুন, কারণ আলাদা ইভেন্টের সিট একে অপরকে প্রভাবিত করে না। একমাত্র সমস্যা গরম ইভেন্ট, যা waiting room আর দ্রুত conditional update সামলায়।
মূল কথা: সিট hold-এ atomic conditional update, hold-এর মেয়াদ স্বয়ংক্রিয়ভাবে শেষ করুন, payment নিশ্চিতকরণ idempotent রাখুন, আর waiting room দিয়ে সিস্টেম বাঁচান।
System Design সিরিজ, পর্ব ৩ (case study): 11 নম্বর (মোট 16)। আগের লেখা: Google Drive-এর মতো file storage ও sync ডিজাইন.


