很多开发者对活码的理解停留在“一个二维码背后绑几个员工”的层面。但作为技术人,我们需要深入到底层:当用户扫码的那一刻,系统内部发生了什么?如何保证千万级流量的稳定分发?今天,我们从架构视角拆解一套完整的活码系统。
一、活码系统的核心链路
一次典型的活码访问链路如下:
- 用户扫描印刷的二维码,解析出一个短链接(如
https://t.cn/abc123)。 - 客户端向短链接服务发起HTTP GET请求。
- 短链接服务重定向到企销宝的动态路由网关(携带参数
code=abc123)。 - 路由网关根据code获取该活码的配置(分流规则、员工池、标签策略)。
- 网关执行分流算法,选择一个目标员工,生成该员工的企微添加链接。
- 返回302重定向,用户最终跳转到企微添加页。
整个流程要求在毫秒级完成,否则会影响用户体验。
二、短链接服务的实现
短链接是活码的入口,需要考虑两个核心问题:唯一性和时效性。
生成算法: 我们采用分布式ID(雪花算法) + Base62编码,生成6-8位的短码。雪花算法保证了全局唯一性和趋势递增,方便分库分表。
存储设计: 短码到原始URL的映射存储在Redis中(热数据)和MySQL中(持久化)。Redis使用String结构,key为短码,value为原始URL,设置合理的TTL(如30天),过期后自动降级查询数据库。
高可用: 短链接服务需要无状态,水平扩展。前置Nginx做负载均衡,后端多实例部署。企销宝的短链接服务经历了多次双11大促,峰值QPS过万,稳如泰山。
三、动态路由网关的设计
网关是活码系统的核心,负责解析规则、执行分流、记录日志。
分流规则引擎: 我们设计了一套可配置的规则DSL,支持:
- 轮询(round-robin)
- 权重(weighted)
- LBS(基于地理位置)
- 时段(time-based)
- 组合规则(如工作时间按权重,非工作时间按轮询)
规则配置存储在MySQL,缓存在Redis。网关每次请求都从Redis获取规则,若不存在则回查数据库并缓存。
分流算法实现(伪代码):
python
复制
下载
def select_employee(rule, context):
if rule.type == 'round_robin':
return round_robin(rule.employees)
elif rule.type == 'weighted':
return weighted_random(rule.employees)
elif rule.type == 'lbs':
return nearest_by_location(rule.employees, context.location)
elif rule.type == 'time':
return select_by_time(rule.employees, datetime.now())
# 组合规则递归处理
四、高并发下的性能优化
缓存预热: 将常用的活码规则提前加载到本地缓存(Caffeine/Guava),减少Redis访问。
异步日志: 扫码日志、添加日志通过消息队列(Kafka)异步落盘,避免同步IO阻塞。
限流熔断: 针对单个活码设置访问限流(如每秒不超过1000次),超过则返回友好提示或降级页面。企销宝在网关层集成了Sentinel,实现精细化的流量控制。
五、数据一致性与最终一致性
分流过程涉及员工接待量的实时计数。我们使用Redis的原子自增操作维护每个员工的“今日已接待数”,并设置每日零点过期。当达到上限时,该员工自动从分流池移除。计数允许轻微不一致(最终一致),因为即使多分配几个,也不会造成严重后果。
六、安全防护
- 签名校验: 所有对网关的请求携带签名,防止恶意刷码。
- IP黑名单: 自动识别异常IP(如短时间内大量请求),加入黑名单。
- URL白名单: 确保重定向的目标URL是企微官方域名,防止开放重定向漏洞。
结语:
活码系统看似简单,实则涉及短链接、规则引擎、高并发、数据一致性等多方面技术。企销宝的活码模块经过多次迭代,形成了稳定高效的架构。希望今天的拆解能给你带来启发。