ULID জেনারেটর পৃষ্ঠা: কেন এটি আলাদা
এই পৃষ্ঠাটি ULID (Universally Unique Lexicographically Sortable Identifier) ফর্ম্যাটে শনাক্তকারী তৈরি করতে পারে। UUID-এর মতো অন্যান্য ফর্ম্যাটের তুলনায় ULID-এর সবচেয়ে বড় পার্থক্য হলো এটি ২৬টি অক্ষরে সীমাবদ্ধ — UUID-এর ৩৬টি অক্ষরের বিপরীতে। শুধু দৈর্ঘ্যই কম নয়, ULID শুধুমাত্র Crockford-এর base32 বর্ণমালা ব্যবহার করে, যা কেস-ইনসেনসিটিভ এবং হাইফেনমুক্ত। প্রথম ১০টি অক্ষর মিলিসেকেন্ড নির্ভুল টাইমস্ট্যাম্প এনকোড করে, যার ফলে ULID-গুলি সৃষ্টিকাল অনুযায়ী লেক্সিকোগ্রাফিক্যালি সাজানো যায়। আর এগুলো URL-সেফ — কোনো এস্কেপিং বা এনকোডিং ছাড়াই সরাসরি URL-এ ব্যবহার করা যায়। এই পৃষ্ঠায় আপারকেস বা হাইফেন টগল নেই, কারণ ULID প্রকৃতিগতভাবেই কেস-ইনসেনসিটিভ এবং হাইফেনবিহীন। র্যান্ডম অংশটি বাকি ১৬টি অক্ষর (৮০ বিট) দখল করে এবং মোট আন্ডারলাইং ভ্যালু ১২৮ বিট।
ULID-এর অভ্যন্তরীণ কাঠামো: টাইমস্ট্যাম্প ও র্যান্ডম অংশ
ULID-এর অভ্যন্তরীণ কাঠামো বোঝা গেলে এর সুবিধাগুলো স্পষ্ট হয়। মোট ১২৮ বিট দুটি ভাগে বিভক্ত:
-
প্রথম ৪৮ বিট (প্রথম ১০ অক্ষর): এটি একটি মিলিসেকেন্ড নির্ভুল টাইমস্ট্যাম্প। অর্থাৎ, ULID তৈরি হওয়ার নির্দিষ্ট মিলিসেকেন্ড পর্যন্ত সময় রেকর্ড করা হয়। এই টাইমস্ট্যাম্প ১৯৭০-০১-০১ (Unix epoch) থেকে গণনা করা হয় এবং ১০৮৯৯ বছর পর্যন্ত কাজ করবে — ১০৮৯৯ সালে শেষ হবে। টাইমস্ট্যাম্পের জন্য Crockford base32-এ ১০টি অক্ষর প্রয়োজন, কারণ base32-এর প্রতিটি অক্ষর ৫ বিট তথ্য বহন করে (১০ × ৫ = ৫০ বিট, কিন্তু ৪৮ বিটের জন্য ১০টি অক্ষরই লাগে — অতিরিক্ত ২ বিট প্যাডিং হিসেবে কাজ করে)।
-
শেষ ৮০ বিট (শেষ ১৬টি অক্ষর): এটি সম্পূর্ণ র্যান্ডম। প্রতিটি ULID-এর জন্য ব্রাউজারের
crypto.getRandomValues()ফাংশন ব্যবহার করে ৮০ বিট র্যান্ডম ডেটা তৈরি করা হয়। এই র্যান্ডম অংশ নিশ্চিত করে যে একই মিলিসেকেন্ডে তৈরি করা ULID-গুলিও ভিন্ন হবে — তবে সম্পূর্ণ গ্যারান্টি নয় (নিচে কোলিশন নিয়ে আলোচনা করা হয়েছে)।
পুরো ১২৮ বিটকে Crockford base32-এ এনকোড করতে ২৬টি অক্ষর লাগে: ১২৮ ÷ ৫ = ২৫.৬, অর্থাৎ ২৬টি অক্ষর (শেষ অক্ষরে ২ বিট প্যাডিং)।
Crockford base32: কেন এই নির্দিষ্ট বর্ণমালা
Crockford base32 বর্ণমালা বিশেষভাবে ডিজাইন করা হয়েছে মানব পাঠযোগ্যতা এবং ত্রুটি হ্রাসের জন্য। বর্ণমালাটি হলো:
0 1 2 3 4 5 6 7 8 9 A B C D E F G H J K M N P Q R S T V W X Y Z
লক্ষ করুন, এখানে I, L, O, U বর্ণগুলো বাদ দেওয়া হয়েছে। কারণ:
- I এবং L: সংখ্যা ১ এবং ছোট হাতের l-এর সাথে গুলিয়ে ফেলা যায়।
- O: সংখ্যা ০-এর সাথে গুলিয়ে ফেলা যায়।
- U: V-এর সাথে গুলিয়ে ফেলা যায় (বিশেষ করে হাতে লেখার সময়)।
এই বর্ণমালার কারণে ULID কেস-ইনসেনসিটিভ। অর্থাৎ, "01ARZ3NDEKTSV4RRFFQ69G5FAV" এবং "01arz3ndektsv4rrffq69g5fav" একই ULID নির্দেশ করে। UUID-তে এটি হয় না, কারণ UUID-তে হেক্সাডেসিমেল অক্ষর (0-9, A-F) ব্যবহার করা হয়, যা কেস-ইনসেনসিটিভ হলেও UUID-র হাইফেন এবং দৈর্ঘ্য সমস্যা তৈরি করে।
Crockford base32-এর আরেকটি বৈশিষ্ট্য: বর্ণমালার প্রতিটি অক্ষর ৫ বিট তথ্য বহন করে। ২৬টি অক্ষরে (২৬ × ৫ = ১৩০ বিট) মোট ১৩০ বিট সম্ভাব্যতা থাকলেও, প্রকৃত তথ্য ১২৮ বিট — বাকি ২ বিট প্যাডিং হিসেবে কাজ করে।
UUID-র সাথে তুলনা: দৈর্ঘ্য, সর্টেবিলিটি ও র্যান্ডমনেস
| বৈশিষ্ট্য | ULID | UUID v4 | UUID v7 |
|---|---|---|---|
| দৈর্ঘ্য | ২৬ অক্ষর | ৩৬ অক্ষর (৩২ হেক্স + ৪ হাইফেন) | ৩৬ অক্ষর |
| সর্টেবিলিটি | টাইমস্ট্যাম্প-ভিত্তিক, মিলিসেকেন্ড নির্ভুল | সম্পূর্ণ র্যান্ডম, সর্ট করা যায় না | টাইমস্ট্যাম্প-ভিত্তিক, মিলিসেকেন্ড নির্ভুল |
| কেস | কেস-ইনসেনসিটিভ | কেস-ইনসেনসিটিভ (হেক্সাডেসিমেল) | কেস-ইনসেনসিটিভ |
| হাইফেন | নেই | ৪টি হাইফেন | ৪টি হাইফেন |
| URL সেফটি | সম্পূর্ণ (কোনো এস্কেপিং প্রয়োজন নেই) | হাইফেন URL-এ কাজ করে, তবে কিছু সিস্টেমে সমস্যা | হাইফেন URL-এ কাজ করে |
| র্যান্ডম বিট | ৮০ বিট | ১২২ বিট (ভেরিয়েন্ট ৪-এ ৬ বিট নির্ধারিত) | ৬২ বিট (ভেরিয়েন্ট ৭-এ ৬৪ বিট নির্ধারিত) |
| টাইমস্ট্যাম্প | ৪৮ বিট (মিলিসেকেন্ড) | নেই | ৪৮ বিট (মিলিসেকেন্ড) |
| মোট বিট | ১২৮ | ১২৮ | ১২৮ |
UUID v4 সম্পূর্ণ র্যান্ডম হওয়ায় ডাটাবেসে B-tree ইনডেক্সে ঢোকানোর সময় পারফরম্যান্স সমস্যা তৈরি করে — নতুন র্যান্ডম UUID ইতিমধ্যে সাজানো পাতায় এলোমেলো জায়গায় পড়ে। ULID এবং UUID v7 টাইমস্ট্যাম্প-ভিত্তিক হওয়ায় নতুন আইডিগুলো ক্রমান্বয়ে ইনডেক্সের শেষে যোগ হয়, যা B-tree-তে ঢোকানোর খরচ কমায়।
তবে UUID v7-এর দৈর্ঘ্য ULID-এর চেয়ে বেশি এবং হাইফেন থাকে। ULID ২৬ অক্ষরেই ১২৮ বিট ধারণ করতে পারে, অথচ UUID v7-কে ৩৬ অক্ষরেই একই বিট ধারণ করতে হয় — কারণ UUID হেক্সাডেসিমেল (৪ বিট প্রতি অক্ষর) ব্যবহার করে, যেখানে ULID base32 (৫ বিট প্রতি অক্ষর) ব্যবহার করে।
সর্টিং আচরণ ও কোলিশন সম্ভাবনা
ULID-এর সবচেয়ে গুরুত্বপূর্ণ বৈশিষ্ট্য হলো লেক্সিকোগ্রাফিক সর্টেবিলিটি। প্রথম ১০টি অক্ষর টাইমস্ট্যাম্প এনকোড করে, যা সময় বাড়ার সাথে সাথে বড় হয়। উদাহরণস্বরূপ:
01ARZ3NDEKTSV4RRFFQ69G5FAV(মিলিসেকেন্ড A-তে তৈরি)01ARZ3NDEKTSV4RRFFQ69G5FAW(একই মিলিসেকেন্ড A-তে তৈরি, র্যান্ডম অংশ ভিন্ন)01ARZ3NDEKTSV4RRFFQ69G5FB0(একই মিলিসেকেন্ড A-তে তৈরি)01ARZ3NDEKTSV4RRFFQ69G5FC0(পরবর্তী মিলিসেকেন্ড B-তে তৈরি)
এখানে, প্রথম তিনটি ULID একই মিলিসেকেন্ডে তৈরি হওয়ায় এদের টাইমস্ট্যাম্প অংশ (01ARZ3NDEKT) অভিন্ন। শুধু র্যান্ডম অংশ (SV4RRFFQ69G5FAV, SV4RRFFQ69G5FAW, SV4RRFFQ69G5FB0) ভিন্ন। এই তিনটির মধ্যে অর্ডার র্যান্ডম অংশের লেক্সিকোগ্রাফিক অর্ডারের উপর নির্ভর করে — যা সম্পূর্ণ এলোমেলো। একই মিলিসেকেন্ডে তৈরি ULID-গুলির মধ্যে কঠোর অর্ডারিং গ্যারান্টি নেই।
চতুর্থ ULID পরবর্তী মিলিসেকেন্ডে তৈরি, তাই এর টাইমস্ট্যাম্প অংশ (01ARZ3NDEKT-এর পরিবর্তে 01ARZ3NDEKU বা তার বেশি) বড় হবে। এটি পূর্ববর্তী তিনটির চেয়ে লেক্সিকোগ্রাফিকভাবে বড় হবে।
কোলিশন সম্ভাবনা: ULID-তে ৮০ বিট র্যান্ডম অংশ ব্যবহার করা হয়। এর মানে হলো, একই মিলিসেকেন্ডে ২^৮০ = ১.২ × ১০^২৪ টি সম্ভাব্য ULID থাকে। প্রতি সেকেন্ডে ১ বিলিয়ন ULID তৈরি করলেও, কোলিশনের সম্ভাবনা ২^৮০ / ১০^৯ = প্রায় ১.২ × ১০^১৫ সেকেন্ড বা ৩৮ মিলিয়ন বছরে একবার। বাস্তবে, এই পৃষ্ঠা সর্বোচ্চ ১০০টি ULID তৈরি করে, তাই কোলিশন প্রায় অসম্ভব। তবে তাত্ত্বিকভাবে সম্ভব বলে এটি গ্যারান্টি নয় — একে বলা হয় "প্রোবাবিলিস্টিক ইউনিকনেস"।
URL সেফটি ও ডাটাবেস ইনডেক্সিং
ULID-এর বর্ণমালা (0-9, A-Z বাদে I, L, O, U) RFC 3986-এর "আনরিজারভড" ক্যারেক্টারের অংশ। এর মানে হলো, একটি ULID-কে URL-এ সরাসরি রাখা যায় — কোনো percent-encoding প্রয়োজন হয় না। যেমন:
https://example.com/user/01ARZ3NDEKTSV4RRFFQ69G5FAV
UUID-তে হাইফেন থাকায় কিছু ক্ষেত্রে সমস্যা হয়, তবে সাধারণত হাইফেনও URL-এ কাজ করে। তবে ULID-তে কোনো বিশেষ ক্যারেক্টার না থাকায় এটি সম্পূর্ণ নির্ভরযোগ্য।
ডাটাবেসে ULID ব্যবহারের সুবিধা: B-tree ইনডেক্সে নতুন আইডিগুলো প্রায় সর্বদা ইনডেক্সের শেষ প্রান্তে যোগ হয় (টাইমস্ট্যাম্প বাড়ার কারণে)। এর ফলে:
- ইনডেক্স পেজ স্প্লিট কম হয়
- ডিস্ক I/O কম হয়
- ইনসার্ট অপারেশন দ্রুত হয়
UUID v4-তে এলোমেলো আইডি B-tree-র যেকোনো জায়গায় পড়তে পারে, যা পেজ স্প্লিট এবং রি-অর্গানাইজেশন বাড়ায়। ULID এই সমস্যা সমাধান করে একটি টাইমস্ট্যাম্প-ভিত্তিক আইডি দিয়ে, যা UUID v7-এর মতোই কাজ করে কিন্তু কম জায়গা নেয়।
লোকাল জেনারেশন ও প্রাইভেসি
এই পৃষ্ঠায় সব ULID জেনারেশন ব্রাউজারে ঘটে। crypto.getRandomValues() ফাংশন ব্যবহার করে ৮০ বিট র্যান্ডম ডেটা তৈরি করা হয়। এটি ওয়েব ক্রিপ্টো API-র অংশ এবং অপারেটিং সিস্টেমের অন্তর্নির্মিত র্যান্ডম নম্বর জেনারেটর (যেমন, Linux-এর /dev/urandom) ব্যবহার করে। কোনো ডেটা সার্ভারে পাঠানো হয় না।
এর মানে হলো:
- আপনার তৈরি ULID-গুলি শুধুমাত্র আপনার ব্রাউজারে থাকে
- আপনি অফলাইন থাকলেও কাজ করে
- থার্ড-পার্টি সার্ভার আপনার আইডি জেনারেশন প্যাটার্ন দেখতে পায় না
- আপনি চাইলে একাধিক ট্যাবে একই পৃষ্ঠা খুলে আলাদা ULID তৈরি করতে পারেন — প্রতিটি ট্যাব স্বাধীনভাবে কাজ করে
ইনপুট হিসেবে আপনি শুধু কাউন্ট (১-১০০) এবং ফর্ম্যাট (ULID) সিলেক্ট করেন। কোনো ব্যক্তিগত তথ্য, আইপি অ্যাড্রেস বা টাইমস্ট্যাম্প সার্ভারে যায় না। জেনারেট করা ULID-গুলি কপি করার জন্য ক্লিক করলেও তা শুধু ক্লিপবোর্ডে কপি হয় — কোনো নেটওয়ার্ক রিকোয়েস্ট হয় না।
প্রায়শই জিজ্ঞাসিত প্রশ্ন (FAQ)
প্রশ্ন: ULID কি UUID-এর চেয়ে বেশি নিরাপদ?
উত্তর: নিরাপত্তা নির্ভর করে ব্যবহারের উপর। ULID-তে ৮০ বিট র্যান্ডম অংশ থাকে, UUID v4-তে ১২২ বিট র্যান্ডম অংশ থাকে। তাই UUID v4 অনুমান করা কঠিন (২^১২২ সম্ভাবনা বনাম ২^৮০)। তবে ULID-র টাইমস্ট্যাম্প অংশ অনুমান করা সহজ — আপনি জানলে কখন এটি তৈরি হয়েছে। তাই ULID এমন জায়গায় ব্যবহার করা উচিত নয় যেখানে আইডি অনুমান করা নিরাপত্তা ঝুঁকি তৈরি করে (যেমন, ইনভয়েস নম্বর)। বরং এটি পাবলিক-ফেসিং আইডি (যেমন, ইউজার আইডি) এবং ডাটাবেস প্রাইমারি কী-র জন্য উপযুক্ত।
প্রশ্ন: একই মিলিসেকেন্ডে তৈরি ULID-গুলি কি সঠিকভাবে সাজানো যায়?
উত্তর: না, সম্পূর্ণভাবে নয়। একই মিলিসেকেন্ডে তৈরি ULID-গুলির মধ্যে অর্ডার র্যান্ডম অংশের উপর নির্ভর করে — যা এলোমেলো। তাই আপনি যদি ১০০টি ULID একবারে তৈরি করেন (যেমন এই পৃষ্ঠা করে), তাদের মধ্যে লেক্সিকোগ্রাফিক অর্ডার র্যান্ডম হবে। তবে ভিন্ন মিলিসেকেন্ডে তৈরি ULID-গুলি সঠিকভাবে সাজানো যাবে। আপনি যদি সময় অনুযায়ী অর্ডারিং চান, তাহলে একটি পৃথক টাইমস্ট্যাম্প কলাম ব্যবহার করুন।
প্রশ্ন: ULID-তে হাইফেন কেন নেই?
উত্তর: ULID ডিজাইন করার সময় Crockford base32 বর্ণমালা ব্যবহার করা হয়, যাতে হাইফেনের প্রয়োজন নেই। হাইফেন UUID-তে গ্রুপিংয়ের জন্য ব্যবহার করা হয়, কিন্তু ULID-তে গ্রুপিংয়ের প্রয়োজন হয় না। বরং হাইফেন না থাকায় ULID কপি-পেস্ট করা সহজ, এবং কোনো ক্যারেক্টার এস্কেপিং বা URL সেফটি সমস্যা হয় না। আপনি চাইলে নিজে থেকে হাইফেন যোগ করতে পারেন, কিন্তু মানক ULID ফর্ম্যাটে হাইফেন নেই।
প্রশ্ন: ULID কি ব্যাকওয়ার্ডস কম্প্যাটিবল?
উত্তর: কিছু ডিগ্রিতে। ULID ফর্ম্যাট UUID-এর মতো নয় — এটি একটি আলাদা এনকোডিং। তবে আপনি যদি ডাটাবেসে UUID কলামে ULID সংরক্ষণ করতে চান, তাহলে ULID-কে UUID-তে রূপান্তর করতে পারেন (বিট লেভেলে রি-ইন্টারপ্রিটেশন করে)। তবে এটি সাধারণত প্রয়োজন হয় না। বেশিরভাগ আধুনিক ডাটাবেস (PostgreSQL, MySQL, SQLite) ULID স্ট্রিং সরাসরি VARCHAR বা TEXT কলামে সংরক্ষণ করতে পারে এবং লেক্সিকোগ্রাফিক সর্টিং কাজ করবে।
প্রশ্ন: এই পৃষ্ঠায় কতগুলি ULID তৈরি করা যায়?
উত্তর: আপনি ১ থেকে ১০০ পর্যন্ত যেকোনো সংখ্যক ULID তৈরি করতে পারেন। কাউন্ট ফিল্ডে একটি পূর্ণ সংখ্যা দিতে হবে — দশমিক বা ঋণাত্মক সংখ্যা গ্রহণযোগ্য নয়। প্রতিবার কাউন্ট পরিবর্তন করলে বা অন্য কোনো অপশন পরিবর্তন করলে (যেমন ফর্ম্যাট পরিবর্তন) লিস্ট রিজেনারেট হয়। আপনি চাইলে প্রতিটি ULID আলাদাভাবে কপি করতে পারেন ক্লিক করে, অথবা "Copy all!" বাটনে ক্লিক করে সম্পূর্ণ লিস্ট কপি করতে পারেন।
প্রশ্ন: ULID কি সময়ের সাথে সাথে আপডেট হয়?
উত্তর: না, একবার তৈরি করার পর ULID পরিবর্তন হয় না। আপনি যে মুহূর্তে "Generate" বাটনে ক্লিক করেন, সেই মুহূর্তের টাইমস্ট্যাম্প ব্যবহার করে প্রতিটি ULID তৈরি হয়। পরবর্তীতে আপনি যদি ফর্ম্যাট বা কাউন্ট পরিবর্তন করেন, তাহলে নতুন টাইমস্ট্যাম্প সহ নতুন ULID তৈরি হবে। পুরনো ULID-গুলি আপনার ব্রাউজার থেকে হারিয়ে যায় (যদি আপনি সেগুলো কপি না করে থাকেন)।