1、整体架构
整体架构分为三层:接入层、缓存层和持久层 。业务方通过 REDtao SDK 接入服务 。如下图:

文章插图
在这个架构中,和 Facebook Tao 不一样的是 , 我们的缓存层是一个独立的分布式集群,和下面的持久层是解耦的 。缓存层和下面的持久层可以独立的扩容缩容,缓存分片和 MySQL 分片不需要一一对应,这样带来了更好的灵活性,MySQL 集群也变成了一个可以插拔替换的持久存储 。
读流程:客户端将读请求发送给 router,router 接收到 RPC 请求后,根据边类型选择对应的 REDtao 集群,根据三元组 ( FromId, AssocType, ToId ) 通过一致性 Hash 计算出分片所在的 Follower 节点,将请求转发到该节点上 。Follower 节点接收到该请求,首先查询本地的图缓存,如果命中则直接返回结果 。如果没有命中,则将请求转发给 Leader 节点 。同样的,Leader 节点如果命中则返回,如果不命中则查询底层 MySQL 数据库 。
写流程:客户端将写请求发送给 router,和读流程一样,会转发到对应的 Follower 节点上 。Follower 节点会转发写请求给 Leader 节点,Leader 节点转发给 MySQL,当 MySQL 返回写入成功后,Leader 会清除本地图缓存对应的 Key,并同步给其他所有 Follower 清除掉该 Key,保证数据的最终一致性 。
2、高可用
REDtao 分为独立的两层:缓存层和持久层 。每一层都保证高可用性 。
自研的分布式缓存:
我们自研了实现图语义的分布式 cache 集群,支持故障自动检测和恢复、水平扩缩容 。
它是一个双层 cache,每个分片都有一个 Leader 和若干个 Follower 。所有的请求都先发给外层的 Follower,再由 Follower 转发给 Leader 。这样的好处是读压力大的时候只需要水平扩展 Follower,单点 Leader 写入的方式也降低了复杂度,更容易实现数据的一致性 。
如果一个副本故障,系统会在秒级别内进行切换 。当持久层发生故障时,分布式缓存层仍然可以对外提供读取服务 。
高可用的MySQL集群:
MySQL 集群通过自研的中间件实现了分库分表方案 , 并支持 MySQL 的水平扩容 。每个 MySQL 数据库有若干从库 , 并且与公司内部其他的 MySQL 运维方案一致,保证高可用性 。
限流保护功能:
为防止缓存击穿导致 MySQL 突发大量请求,从而导致 MySQL 宕机,我们通过限制每个主节点最大 MySQL 并发请求数来实现限流保护 MySQL 。达到最大并发请求限制之后的请求会被挂起等待,直到已有请求被处理返回,或者达到等待超时请求被拒绝不会被继续请求到 MySQL。限流阈值在线可调,根据 MySQL 集群规模调整对应限制 。
为防止爬虫或者作弊用户频繁刷同一条数据,我们利用 REDtaoQueue 顺序执行对写入或者点查同一条边的请求 , 队列长度会被限制 , 控制同一时间大量相同的请求执行 。相比于单个全局的队列控制所有请求的方式 , 基于每个请求的队列可以很好地限制单个同一请求 , 而不影响其他正常请求 。
3、极致性能
数据结构的设计是 REDtao 高性能的重要保证 。我们采用了三层嵌套 HashTable 的设计, 通过根据某个起点 from_id 从第一级 HashTable 中查找到 REDtaoGraph , 记录了所有 type 下对应的所有的出边信息 。接着,在第二级 HashTable 中,根据某个 type_id 查找到 AssocType 对应某个 type 下边所有出边的计数、索引以及其他元数据 。最终在最后一级 HashTable,通过 AssocType 的某个 to_id 查找到最终边信息 。我们记录了创建时间、更新时间、版本、数据以及 REDtaoQueue,time_index 则对应根据创建时间排序列表 。最后一级 HashTable 以及索引限制存储最新的 1000 个边信息,以限制超级点占据过多内存 , 同时集中提高最新热数据的查询命中率以及效率 。REDtaoQueue 用于排队当前某个关系的读写 , 只记录了当前最后一个请求的元数据 。每次查询或写入时,首先查询 REDtaoAssoc,若缓存不存在,则会首先创建只包含 REDtaoQueue 的对象;若缓存已存在,则会更新队列元数据 , 将自己设置为队列的最后一个请求,并挂起等待被执行 。

文章插图
通过这种多层 hash+ 跳表的设计,我们能高效地组织点、边、索引、时间序链表之间的关系 。内存的申请、释放在同一个线程上完成 。
在线上环境中,我们的系统可以在一台 16 核的云厂商虚拟机上跑到 150w 查询请求/s,同时 CPU 利用率仅有 22.5%。下方是线上集群的一个监控图,单机的 QPS 到达 3w,每个 RPC 请求聚合了 50 个查询 。
推荐阅读
- 常见的负载均衡算法及其适用场景
- 远程运维是什么?运维是什么?运维工程师是干嘛的?
- 反向代理服务器与CDN的协同作用
- 号称“可穿在身上”的ChatGPT,爆火的Ai Pin是创新还是又一次概念炒作?
- 轻松玩转Python,五个步骤打造惊艳的折线图
- C++初始化列表:探索多种初始化方式
- .NET Core中一些优秀的项目和框架
- 掌握Python的解包技巧:*和**的最全用法
- 从零到SQL注入防护大师,打造安全的Python应用程序
- 下雪的九寨沟有多绝?戳图欣赏!
