今年是微信读书上线10周年,后台架构也伴随着微信读书的成长经历了多次迭代与升级。每一次的组件升级与架构突破,在一个运行了10年的系统上落地都不是一件容易的事情,需要破釜沉舟的决心与胆大心细的业务联动。本文简要概述微信读书后台团队近几年的一些架构迭代以及背后的思考。
关注腾讯云开发者,一手技术干货提前解锁👇
腾讯云开发者
腾讯云官方社区公众号,汇聚技术开发者群体,分享技术干货,打造技术影响力交流社区。
957篇原创内容
公众号
前言
今年是微信读书上线10周年,后台架构也伴随着微信读书的成长经历了多次迭代与升级。每一次的组件升级与架构突破,在一个运行了10年的系统上落地都不是一件容易的事情,需要破釜沉舟的决心与胆大心细的业务联动。
微信读书经过了多年的发展,赢得了良好的用户口碑,后台系统的服务质量直接影响着用户的体验。团队多年来始终保持着“小而美”的基因,快速试错与迭代成为常态。后台团队在日常业务开发的同时,需要主动寻求更多架构上的突破,提升后台服务的可用性、扩展性,以不断适应业务与团队的变化。
整体架构
微信读书是独立于微信的App,且由于历史原因,开发及运维环境均存在一定的差异与隔离。因此,微信读书的后台服务实现了从接入层到存储层的一整套完整架构。
架构上分解为典型的接入层、逻辑层和存储层:
具体的业务逻辑不再赘述,下面简单介绍下微信读书近几年在后台架构上的一些演进。
RPC框架
微信读书后台微服务源于Hikit框架,采用C++开发。该框架诞生于广研、QQ邮箱年代,在性能、容灾、运维、监控层面都经受了线上的考验,在微信读书上线初期作为主要框架,支撑了后台服务长达数年。
随着微信读书的发展,越来越多异构的系统发展起来,例如推荐算法系统是独立部署在TKE上的容器服务,采用GO语言开发,好处是历史负担少,运维更加方便、开发更加便捷。两套系统同时存在带来的问题是如何做好服务治理,推荐系统需要频繁调用后台基础模块获取用户数据,必须要有一套完善的路由管理、容灾机制,且考虑到是异构服务,开发语言也不相同,如果为每种语言都定制开发一套服务治理框架,代价会非常高。在这个阶段,我们开发了WRMesh框架,采用Sidecar+Business的方式解决这个问题。
Sidecar专注于处理网络层的逻辑,和Business业务层分开为两个进程,由WRMesh脚手架生成代码,上层业务无需感知。Sidecar集成了Hikit框架中用于服务治理的核心逻辑,通过UnixSocket与Business进行通信,代理Business的所有网络读写。当Business进程中需要发起网络请求时,由WRMesh生成的Client代码会自动识别当前是否在mesh环境中,并转发请求给Sidecar,由Sidecar完成接下来的网络处理。因此,Business进程可以由任意语言任意框架开发,只要遵循Sidecar的通信协议,只需要薄薄的一层网络协议转换即可接入到Hikit的服务治理框架中。另外,对于某些有特殊路由逻辑的Client,如KV访问、Batch请求等,代理转发并不能满足要求,因此Sidecar还提供了插件能力集成这些Client逻辑,最大限度为异构Business业务提供原生C++的能力。
随着WXG容器平台P6N的建设越来越完善,许多微信的能力也是基于P6N提供,我们也在思考如何逐步迁移到P6N。由于微信读书后台运维目前依赖于企微团队,有独立于P6N的一套运维体系,我们负责业务和架构开发。如果要一刀切把所有后台服务迁移至P6N,将会面临几个问题:
考虑到人力成本及投入性价比,我们最终采用了折衷的方案。一方面我们保留了依赖于企微的运维环境,保障绝大多数现成服务的稳定运行。另一方面,对于微信P6N中的服务,我们搭建了比较完善的Proxy层,例如Svrkit代理、WQueue代理等,两套架构可以方便进行互通,最大限度的在原有基础上接入微信的新能力。目前,微信读书已顺利接入如WQueue、FKVOL、SimOL、TFCC等众多微信的能力。
书籍数据中台建设
书籍是微信读书的内容根基,书籍数量的多少、书籍质量的好坏,很大程度上决定了用户是否选择微信读书作为阅读App。过去,我们依托阅文集团提供电子书资源,免去了书籍上架前繁琐的处理流程,包括排版、审校、元信息管理、更新管理等,后台服务只需要对接阅文API即可方便获取书籍数据,我们只需要关注书籍在平台的存储管理和分发流转即可。
近几年,电子书行业的大环境发生变化,一方面,用户对书籍品类多样性、内容质量有更高的诉求,另一方面,平台对成本、版权等行业因素也更为敏感。因此,我们也在积极探索自签版权,甚至是自出品的模式,尝试走更多不一样的道路。从后台角度而言,从过去单一依赖阅文集团API的模式,慢慢转为开放更多的书籍管理接口,形成书籍数据中台模式,为上层运营同学搭建内容管理平台,让更多人可以方便参与到电子书的制作、排版、上下架、运营管理当中。
以EPUB为例,从内容产出到上架到微信读书,大致经历以下阶段:
回到最初的目标,我们希望把更多的书籍管理能力开放出来,对上层屏蔽电子书底层的后台逻辑,让运营同学可以更专注于书籍的管理。因此,我们构建了如下书籍数据中台:
后台服务拆分开StoreAPI和StoreSvr,StoreAPI提供书籍管理的接口,由运营同学搭建的内容平台与StoreAPI交互,完成书籍的管理工作。StoreSvr一方面接受StoreAPI的请求,更新书籍数据,另一方面为现网用户提供高可用的服务。StoreAPI提供了如下接口能力:
此外,如上所述,划线位置和阅读进度等核心UGC数据由于是按文件偏移记录,当书籍文件替换后,这些数据会发生错位,如果不能及时修复,将对用户体验造成巨大影响。尤其在一些热门书籍里,单本书里与位置相关的UGC数据往往能达到亿级别,由于文件替换后位置的偏移具有随机性,并不能采用简单的映射方式解决,在过去,我们开发了专门的修复服务来完成这个事情,针对每一个UGC内容,采用全文模糊查找的方式重新计算新的偏移,并更新的UGC正排、书籍倒排等多个存储中。但随着用户数据越来越多,书籍替换频率越来越频繁,修复不及时或者失败的问题逐渐暴露出来:
针对上面的问题,我们重新设计了修复服务,目标是最大限度缩短修复时间,并且让整个过程是可靠的。为此,我们先首手考虑业务流程,我们发现在书籍上架前,运营同学本来就需要依赖UGC的修复情况做前置判断是否覆盖上架,这个过程中虽然是对UGC抽样评估,如果能对这个修复映射结果进行缓存,在正式替换文件后,也能一定程度提升修复速度。在核心修复流程中,我们进行了较大的重构,把单本书的修复任务拆解成多个子任务,存储在Chubby上,多机器抢锁共同消费这些任务,由于任务有落盘,在服务上线重启过程中,也能马上恢复。修复过程涉及大量的KV写入,并发太高时容易命中单key的限频或者版本冲突,我们为此开发了针对K-Str和K-Table的写入中间件,可以在内存中聚合一批请求进行批量合并写入,缓解KV层面的失败。
目前,微信读书已通过内容平台完成了多家版权方自签,并在探索自出品等内容创作新形式。
账号系统可用性建设
账号是微信读书后台系统的基石,承担了登录、会话密钥生成与派发、用户资料管理等核心功能,所有的用户请求都需经过账号系统进行鉴权验证用户身份,但凡有一点系统抖动都会影响到整个App的正常使用,严重者还会导致账号被踢出无法再次登录。
账号系统的架构在微信读书诞生之初便一直沿用,同一个号段的账号服务AccountSvr和MySQL部署在同一台机器上,备机采用主从同步的方式获取数据,当主机不可用时,备机承担了所有读请求。在某些场景下,为了能使访问备机时也具备一定的写入能力,曾经魔改过主备逻辑,但一切都显得治标不治本,且引入了更复杂的系统特性,整个架构略显混乱。在机器裁撤、数据扩容过程中,曾造成过几次严重故障,导致App不可用,严重影响用户体验。究其原因,是因为当时基础设施还不完善,缺少高性能高可靠的强一致存储,MySQL也是手动搭建的,运维成本和风险都非常高。
为了彻底解决这个历史包袱,我们在2024下定决心对其进行重构。重构就意味着要抛弃现有MySQL这套臃肿的存储方案,把数据迁移到新的存储组件上,这里涉及到的挑战点如下:
背水一战,没有退路可言。在经历了多次论证后,我们决定采用Paxosmemkv作为新的存储组件,全内存、多副本、强一致的特性,很适合作为账号系统的底层存储。同时,我们为整个迁移过程制定了周密的方案,把每一步进行了分解,且要求每个环节可灰度可回退,同时要做好数据的一致性检查。在完成数据迁移后,我们还需要对AccountSvr进行重构,抛弃按号段的账号分配、路由、缓存逻辑,以全新的视角设计更简洁的架构。
内容召回演进
以往微信读书的搜索仅限于基于书名、作者等维度的文本召回,通过自建的全内存索引服务实现书籍的检索。全文检索则基于ES搭建,采用规则分段的方式建立索引,能满足读书大部分场景的需要。
在大语言模型迅速发展的近两年,微信读书作为一个庞大的内容知识库,具有大量的书籍原文资源,同时,用户在微信读书也留下了大量的文字内容,如书评、想法等,这些内容构成了AI问书的内容基石,也是AI问书区别于其它问答工具的核心优势。基于微信读书构建RAG召回系统,核心挑战如下:
为此,我们针对微信读书不同的RAG使用场景,设计了如下召回架构:
我们把数据划分成两类:全局公开可搜以及用户个人可搜。
对于全局公开可搜索的数据,如库内电子书的全文、书籍大纲、书评、人工知识库等,我们构建了一套入库流程,能对源信息进行语义分段、生成正排倒排,语义分段基于开源的chunk模型进行微调,正排基于fkv,倒排则基于ES构建,ES提供了DiskANN方案,通过设置合理的缓存和分片,能在存储成本和召回效率之间取得不错的平衡。对于 App 内主搜等低时延场景,为了满足多种定制化检索需求,我们自建了基于内存索引的Searchsvr服务,支持索引落盘,可以在毫秒级返回电子书搜索结果。
对于用户个人数据,如导入书全文、个人想法等,特点是数据量大但使用频率不高,不需要针对全网用户进行检索,如果采用上述方案,会带来成本灾难,性价比极低。为此,我们按用户及物料的维度,基于USearch、Xapian等方案构建了向量及文本索引,这些组件的优势在于可以把单个索引存储成文件的形式,便于落盘,配合一些量化的方法,可以把大大压缩索引大小。在构建索引阶段,按用户+类型构建出不同的索引,并存储在低成本的COS上,当用户需要检索召回时,采用读时加载的方式实时进行召回,结合CFS进行预热可以大大提升检索速度。当检索完成后,定时淘汰策略会把长期不用的索引从CFS中清理,降低存储成本。
写在最后
虽然微信读书已经发展了十个年头,但我们的脚步从未停止。
在日常业务开发之余,我们也从未停止思考如何让系统能走得更远、更稳健,抓住每一个可能的优化点,随时做好准备,迎接下一个精彩的十年。