Webman短链接分库分表核心是解决ID耗尽与QPS瓶颈,须从路由可控、ID分散、连接隔离三处下手:用Snowflake变种生成Base62短码,短码前两位哈希分库+按月分表,PDO按库隔离禁持久化,缓存穿透需锁+空值标记。

Webman 做短链接生成器,分库分表不是为了“炫技”,而是解决两个硬伤:单表主键 ID 用完(比如 bigint 溢出)、单库写入 QPS 上不去(高频生成 + 高频跳转)。真要扛住日均亿级生成+十亿级跳转,必须从路由可控、ID 分散、连接隔离三处下手。
短链接 ID 不能依赖自增主键
直接用 MySQL AUTO_INCREMENT 当短码,线上跑不过三个月。原因很实在:ID 线性增长,热点集中在最新几张表;并发插入争抢同一张表的自增锁;一旦某库宕机,整个 ID 生成链就断。
- 改用 Snowflake 变种:Worker ID 按分库编号分配(如库
short_0对应worker_id = 0),时间戳右移 12 位,序列号 12 位,生成 64 位整数后转 Base62(非 Base64,避免 URL 编码问题) - 禁止把生成逻辑塞进事务里——
INSERT ... SELECT或REPLACE INTO都会锁表,高并发下直接拖垮吞吐 - 预生成池更稳妥:后台协程每 5 秒批量生成 1000 个未使用的
short_code,存 Redis List(short:pool),业务层LPOP取用,失败则 fallback 到实时计算
跳转查询必须命中单库单表,不能 UNION ALL 扫全库
用户点短链,GET /s/abc123,响应必须在 20ms 内完成。如果每次都要遍历 short_0 到 short_9 十个库查 short_code = 'abc123',延迟直接翻十倍,还容易触发慢查询告警。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 短码前两位做分片键:
abc123→ 取hash('ab') % 10→ 路由到short_2库;表名再按月分(link_202606),这样一次定位到唯一物理表 - 建唯一索引必须包含分片字段:
UNIQUE KEY uk_short_code_shard (short_code, shard),否则跨库重复短码无法拦截 - 禁止在模型层写
where('short_code', $code)后让 ORM 自动路由——ThinkORM 的getTable()不支持运行时传参分库,得自己封装Db::connection("short_{$shard}")->table("link_{$month}")->where(...)
PDO 连接必须按库隔离,且禁用持久化
Webman Worker 常驻内存,一个没关紧的连接,可能在凌晨三点还在往已下线的 short_5 库发心跳,报错 MySQL server has gone away 却没人发现。
- 每个分库初始化独立 PDO 实例,绑定到容器时带明确命名:
Container::set('short_db_0', new PDO($dsn0, $user, $pass, [PDO::ATTR_PERSISTENT => false])) - 别在
onWorkerStart里new PDO后赋值给静态变量——多进程间不共享,且 PHP 8.5.5 对静态资源序列化有更严校验,容易 crash - 连接异常必须显式关闭:
try { $pdo->query(...); } catch (\PDOException $e) { $pdo = null; },否则连接泄漏会随 Worker 生命周期累积
缓存穿透防护要覆盖“空结果”和“过期瞬间”
短链跳转是典型的读多写少场景,但恶意刷不存在的 /s/zzzzzz 或刚好在缓存过期那 1ms 内涌进 1000 请求,数据库立马被打满。
- Redis Key 必须带版本号和空值标记:
short:code:abc123:v2存真实数据,short:miss:abc123:v2存空结果(TTL 设为 1 分钟,比业务过期时间短) - 查缓存 miss 时,先用
SETNX short:lock:abc123:v2 1 EX 3抢分布式锁,抢到才查 DB,查完立刻写缓存并删锁;没抢到就sleep(10)后重试,避免雪崩 - 请求级缓存兜底:在 Controller 里用
static $cache = []记一次请求内重复查同一个短码,防止同请求内多次穿透
真正难的不是分多少库、建多少表,而是每次生成或跳转时,你能否在 10 行代码内确定:该去哪个库、哪张表、用哪个连接、查什么索引、缓存怎么设、失败怎么兜。这些决策点一旦写死在构造函数或静态属性里,Webman 的常驻特性就会把它变成定时炸弹。


















