内容提要
Canva为管理数亿用户会话,将撤销记录以紧凑二进制格式存入S3,按30分钟分块,网关启动时仅下载最近12小时数据。异步工作进程批量更新块,用条件PUT避免冲突。此方案将内存占用减少87.5%,部署更快,数据库负载随写入量可预测扩展,优于传统Redis缓存方案。
延伸解读
为什么选择S3而非Redis
文章指出,虽然Redis是常见的缓存方案,但Canva最终选择了S3,主要原因是Redis通常不具备完全持久化配置,且需要额外管理集群,可能只是把问题从MySQL转移到Redis。S3则提供强持久性保证,并支持低成本高效读取大文件,更符合其大规模会话撤销记录的需求。
二进制格式与内存优化
Canva将撤销记录压缩为16字节的二进制格式,并排序存储,使得网关可以直接在下载的字节上进行二分查找,无需转换。这一改变将内存占用减少了87.5%,因为不再需要为每条撤销记录维护多个Java对象,显著降低了内存开销。
异步写入与并发控制
为避免每次撤销都重写整个S3块,Canva采用异步工作进程批量更新,并使用条件PUT实现乐观并发控制,确保数据不丢失。尽管理论上O(N^2)的复杂度看似不高效,但实际测试表明,批量处理数百条撤销记录时,写入吞吐量超过每秒2000条,远超预期需求。
部署性能与数据库负载的改善
新方案显著提升了部署速度,并减少了对数据库读副本的依赖,仅保留两个用于冗余。数据库负载从依赖历史写入量和网关实例数,转变为随写入吞吐量和站点流量可预测扩展,使系统更具可扩展性和稳定性。
Q&A
Canva如何解决大规模用户会话撤销时的数据库负载问题?
Canva将撤销记录以紧凑的二进制格式存储在S3中,按30分钟分块,网关启动时只下载最近12小时的数据,并通过异步工作进程批量更新块,使用条件PUT避免冲突,从而减少了数据库负载。
Canva为什么选择S3而不是Redis作为会话撤销缓存?
因为Redis通常不具备完全持久化配置,且需要管理集群,会增加复杂性;而S3提供强持久性保证,支持高效读取大量数据,且成本低,更适合存储大文件。
Canva的会话撤销记录在内存中是如何存储的?
每个撤销记录包含主体(principal)和登录时间戳,通过位操作压缩为16字节,多个记录组成扁平数组,按主体排序,支持二分查找,网关直接操作下载的字节,无需转换。
Canva如何保证S3中撤销块的一致性?
使用条件PUT请求实现乐观并发控制,更新时断言块未被修改,创建新块时检查是否已存在,确保读-修改-写操作只追加不丢失数据,同时用ZooKeeper领导选举减少冲突。
Canva的会话撤销系统如何实现高可用?
运行多个异步工作进程副本,通过ZooKeeper领导选举优化,但正确性依赖条件PUT,即使节点暂停后恢复也不会覆盖其他节点的更改。
Canva的会话撤销系统如何扩展以处理大量写入?
虽然构建块的时间复杂度为O(N^2),但通过批量处理数百个撤销记录,实际吞吐量超过每秒2000条,满足未来需求,且数据库负载随写入量可预测扩展。
Canva的会话撤销系统上线后带来了哪些改进?
部署速度提升,数据库读副本减少到两个,内存占用减少87.5%,数据库负载从依赖历史写入和网关数量变为随写入量可预测扩展。