Access Token 的缓存是系统性能和健壮性的核心。不同的缓存存储方案适用于不同的系统架构。我们将对比三种主流方案:本地内存、分布式缓存(Redis)和持久化数据库。
1. 本地内存缓存
这种方式将 Access Token 存储在应用程序实例的内存堆中。
| 特点 | 描述 |
| 优点 | 极速读写(毫秒级),无需网络 I/O,实现简单。 |
| 缺点 | 无法共享,每个应用实例都有自己的 Token。 |
| 并发安全 | 需要使用进程内锁(如sync.RWMutex)保证读写原子性。 |
| 适用场景 | 单体应用或 仅有一个应用实例的微服务。 |
| 局限性 | 不适用于需要水平扩展的分布式集群,因为会导致多个实例同时刷新 Token,造成浪费和限流风险。 |
2. 分布式缓存(Redis/Memcached)
将 Access Token 存储在一个独立、共享的分布式缓存服务中。
| 特点 | 描述 |
| 优点 | 数据共享,所有应用实例都能访问。读写速度快,支持 TTL(过期时间)。 |
| 缺点 | 引入网络 I/O 延迟(但通常极低)。需要额外维护一个缓存服务。 |
| 并发安全 | 必须使用分布式锁(如 Redis 的SET NX EX命令)来保证 Token 刷新的原子性。 |
| 适用场景 | 微服务架构、需要高可用和水平扩展的集群。 |
| 最佳实践 | Token 存储在 Redis 中并设置 $7000$ 秒的 TTL,由独立的 Token Keeper 服务负责刷新。 |
3. 持久化数据库缓存(MySQL/PostgreSQL)
将 Access Token 存储在业务数据库的一个表中。
| 特点 | 描述 |
| 优点 | 持久化,数据库自带高可用和备份机制。共享数据。 |
| 缺点 | 读写延迟高(相比 Redis),引入数据库 I/O 压力。 |
| 并发安全 | 必须使用数据库事务锁(如SELECT FOR UPDATE)来保证刷新操作的原子性。 |
| 适用场景 | 低频API 调用或对数据可靠性要求极高,且不希望引入额外缓存服务的小型系统。 |
| 局限性 | 不适合高并发的群发场景,数据库可能成为瓶颈。 |
4. 总结与推荐
在处理企业微信 Access Token 的场景中,分布式缓存(Redis)具有压倒性的优势,是高并发、高可用系统的唯一推荐方案。
| 方案 | 适用架构 | 核心优势 | 并发实现方式 |
| 本地内存 | 单体应用/单实例服务 | 读写速度最快 | 进程内锁 (RWMutex) |
| 分布式缓存 | 微服务集群(推荐) | 高可用、共享、高性能 | 分布式锁(SET NX EX) |
| 持久化 DB | 低并发系统 | 数据持久化、高可靠 | 数据库事务锁 |
5. 分布式锁的技术实现细节
以 Redis 为例,分布式锁的实现至关重要,它确保了在 $7200\text{s}$ 的周期内,只有一个实例能成功执行 Token 刷新 API 调用。
// 伪代码:尝试获取刷新锁 // NX: 仅在 Key 不存在时设置 // EX 5: 设置 Key 的过期时间为 5 秒(防止实例宕机导致死锁) SUCCESS = REDIS.SET('token_refresh_lock', 'instance_id', NX, EX 5) IF SUCCESS: // 执行 Token 刷新 API 调用 REFRESH_TOKEN_AND_CACHE_NEW_VALUE() // 释放锁 REDIS.DEL('token_refresh_lock') ELSE: // 刷新操作正在进行,等待新 Token 写入缓存 WAIT_AND_READ_TOKEN_FROM_CACHE()