“点击链接,立即领取福利!”——这样的短信你一定收到过。背后的短URL技术,是互联网时代的“隐形桥梁”。但当系统需要处理百亿级短URL时,如何确保每个链接绝不重复?如何在高并发下依然稳如泰山?本文将带你深入Java短URL生成器的设计核心,破解百亿级无冲突的终极密码。

短URL的本质是将长字符串压缩为6-8位字符。以6位Base62编码为例,理论容量为62^6≈568亿,但实际业务中需考虑哈希冲突和预分配效率问题。
痛点:传统哈希算法(如MD5)生成的短码可能重复,而数据库查询去重在高并发下会成为性能瓶颈 。
2.吞吐量极限假设系统日均生成500万短URL,高峰期QPS可能突破4万,要求响应时间≤10ms。若每次生成都查库校验,数据库将瞬间崩溃。
3.存储与成本百亿级数据需占用12TB+存储空间(每条记录约1KB),传统关系型数据库难以支撑,且需考虑冷热数据分离和过期清理。
破局之道:四大核心设计1.唯一ID生成:从“雪花”到“粮仓”雪花算法(Snowflake): 分布式ID生成器,通过时间戳+机器ID+序列号生成唯一长整型ID。但需解决机器ID分配问题(如ZooKeeper协调)。// 示例:Snowflake生成ID public Snowflake { public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) throw new RuntimeException("时钟回拨!"); if (timestamp == lastTimestamp) sequence = (sequence + 1) & MAX_SEQUENCE; else sequence = 0L; lastTimestamp = timestamp; return (timestamp << TIMESTAMP_SHIFT) | (datacenterId << DC_SHIFT) | (machineId << MACHINE_SHIFT) | sequence; } } 预生成“粮仓”: 提前批量生成短码池(如144亿个),存储于HDFS或Redis。请求时直接分配,避免实时计算冲突。 优势:离线生成时用布隆过滤器去重,上线后无锁分配,吞吐量提升10倍+。2.编码策略:Base62的“变形记”Base62 vs Base64: Base62(0-9a-zA-Z)剔除+和/,避免URL特殊字符问题。6位Base62可覆盖568亿组合,满足百亿需求。// Base62编码示例 public static String encode(long num) { StringBuilder sb = new StringBuilder(); char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); while (num > 0) { sb.append(chars[(int)(num % 62)]); num /= 62; } return sb.reverse().toString(); } 动态长度优化: 根据ID大小动态调整编码长度(如1亿以内用5位),减少存储空间。3.存储架构:分库分表与缓存杀手锏分库分表: 按短码首字母分16个库(0-9a-f),每个库再分1024张表,支撑百亿级数据。多级缓存:Redis热数据:缓存最近7天生成的短URL,命中率超90%。本地缓存:Guava Cache存储高频访问数据,响应时间≤1ms。// Redis缓存示例 public String getLongUrl(String shortCode) { String cacheKey = "url:" + shortCode; String longUrl = redis.get(cacheKey); if (longUrl != null) return longUrl; longUrl = database.query("SELECT long_url FROM url_map WHERE short_code=?", shortCode); if (longUrl != null) redis.setex(cacheKey, 3600, longUrl); return longUrl; } 4.冲突处理:布隆过滤器的“防火墙”预检冲突: 在预生成阶段,用布隆过滤器(如Guava BloomFilter)判断短码是否已存在,误判率可控制在0.1%以下。// 布隆过滤器示例 BloomFilter<String> filter = BloomFilter.create(Funnels.stringFunnel(), 1000000, 0.001); if (!filter.mightContain(shortCode)) { filter.put(shortCode); saveToDB(shortCode, longUrl); } 动态扩容: 当预生成池使用率超过80%时,触发异步任务补充新短码,避免分配中断。性能压顶:高并发的“三重防护”1.异步化与批量处理批量发号:每次从数据库获取1万个ID段,内存中自增分配,减少数据库压力。写合并:通过Kafka队列缓冲写请求,批量落库,降低IO次数。2.负载均衡与限流Nginx加权轮询:将请求分发到多个生成器节点,避免单点故障。Sentinel限流:针对IP或用户实施QPS限制,防止恶意刷量。3.监控与熔断Prometheus+:实时监控QPS、缓存命中率、数据库负载。Hystrix熔断:当数据库响应超时≥500ms,自动熔断并降级为预生成模式。从百亿到万亿,短URL技术的演进永无止境。无论是预生成池的“粮仓战略”,还是雪花算法的“时空魔法”,其核心始终是平衡性能、成本与可靠性。未来,随着边缘计算和AI预测的加入,短URL或许会成为更智能的“流量指挥官”,而我们只需记住:技术永远服务于人。