Ensuring Globally Unique CDN Filenames Using Timestamp, Base62, and Redis Locks
This article explores several strategies—timestamp with random numbers, MD5 hashing, UUIDs, and an optimized Base62 conversion combined with Redis‑based locking—to generate short, globally unique CDN file names for an OSS upload platform.
Background
Within the internal CDN file upload platform, files are stored in Alibaba Cloud OSS and served via CDN links. The CDN cache uses a persistent strong cache (Cache-Control: public, max-age=31536000), requiring each uploaded file name to be globally unique to avoid overwriting.
Unique Naming Methods
Method 1: Timestamp + Random Number
The simplest approach combines the current timestamp with a few random digits.
<code>const name = Date.now() + Math.random().toString().slice(2, 6); // '17267354922380490'</code>Optimizing by converting both parts to base‑36 reduces the length.
<code>const name = Date.now().toString(36) + Math.random().toString(36).slice(2, 6); // 'm191x7bii63s'</code>This method is straightforward and satisfies most needs, though a tiny collision probability remains.
Method 2: File MD5 Hash
Using the file’s MD5 hash as its name provides a fingerprint that is virtually unique.
<code>const crypto = require('crypto');
const name = crypto.createHash('md5').update([file]).digest('hex'); // 'f668bd04d1a6cfc29378e24829cddba9'</code>The downside is the relatively long filename.
Method 3: UUID
UUIDs have an almost zero collision probability but also result in long strings, e.g.,
279e573f-c787-4a84-bafb-dfdc98f445cc.
Final Solution
We refined the timestamp‑plus‑random approach to meet two goals: keep CDN links short and guarantee uniqueness.
Key optimizations:
Leverage the case‑sensitivity of CDN URLs and encode the numeric part in base‑62 (digits, uppercase, lowercase) to shorten the string.
Define the timestamp as the milliseconds elapsed since 2024‑01‑01 instead of the Unix epoch, drastically reducing its magnitude.
Implementation example:
<code>/**
* Convert a decimal integer to base‑62
*/
function integerToBase62(value) {
const base62Chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const base62 = base62Chars.length;
value = parseInt(value);
if (isNaN(value) || !value) {
return String(value);
}
let prefix = '';
if (value < 0) {
value = -value;
prefix = '-';
}
let result = '';
while (value > 0) {
const remainder = value % base62;
result = base62Chars[remainder] + result;
value = Math.floor(value / base62);
}
return prefix + result || '0';
}
const part1 = integerToBase62(Date.now() - new Date('2024-01-01').getTime()); // 'OkLdmK'
const part2 = integerToBase62(Math.random() * 1000000).slice(-4); // '3hLT'
const name = part1 + part2; // 'OkLdmK3hLT'
</code>To eliminate the random segment entirely, we ensure that only one filename is generated per millisecond across all service instances using a Redis‑based lock.
<code>// Pseudo‑code
async function getFileName() {
// Wait for the lock to be released; concurrent calls wait at least 1 ms
await waitLockRelease();
return integerToBase62(Date.now() - new Date('2024-01-01').getTime());
}
const name = await getFileName(); // 'OkLdmK'
</code>The
waitLockReleasefunction is implemented with Redis to coordinate multiple Node.js instances, guaranteeing cross‑process uniqueness. An additional single random digit is kept as a safety margin, resulting in a final filename length of just 7 characters with 100 % uniqueness.
Conclusion
Although the problem appears simple, achieving a rigorous, collision‑free solution required base‑62 encoding and distributed locking. The techniques shared here can help developers create compact, globally unique CDN filenames.
Goodme Frontend Team
Regularly sharing the team's insights and expertise in the frontend field
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.