《大型系统应用架构实践》笔记:全球区域化部署与多层路由设计

书籍链接:https://book.douban.com/subject/34782232/ 主要针对第二章的全球区域化部署技术 1 总体架构 基本原则 问题 解决方案 总体架构 2 路由服务 2.1 路由服务架构 透传技术优势: 1、无需在每一层维护一个路由表,不用过多关注路由数据一致性问题。 2、无需每次都调用路由表RPC服务,对RPC服务的依赖过大,调用量过高。 2.2 路由表设计 1、基本模型 类似位图,通过用户id将bitmap对应的位置置为1。但是我们不仅需要存储用户是否存在的信息,还需要存储用户到机房的路由,所以用4个二进制位来存储用户到机房的映射。 前三位:机房标识 最后一位:用户状态 2、分段存储 为了解决ID分布不均匀,存储浪费的问题,采取分段模式进行存储。用户没命中的段为null,不会占用内存。 3、逻辑机房 1、路由信息巨大,机房迁移成本很高。 2、使流量均匀分布。 4、一致性保障 定期MD5进行对比 2.3 路由表更新机制 基于Zookeeper实现,引入“禁写”状态,即用户的路由表更新时,该用户无法进行业务写入,从而确保业务数据的全局一致性。架构如下: 整体流程 2.4 用户路由更新方案 1、确定用户归属机房 通过对各个机房的访问统计,将延迟最少的机房确认为最近的机房。 2.5 多层路由实现 1、统一接入层路由技术 为所有网站用户提供统一的接入点,对多区域进行对等部署,并将用户归属到不同的区域。 方案:Openresty + Lua共享内存 + Redis + ProxyServer 2、服务层路由技术 业务相关,处理不同类型的数据,如:独享数据、共享数据。 1)用户优先级原则,如买家 > 卖家 > 平台运营人员。 2)数据类型及处理方法 只读类型:不需要实时一致;处理:数据异步复制 独享类型:只有一个用户可以对数据进行变更。处理:本地读写 共享数据:多个用户需要共同变更同一条数据。处理:优先级最高的用户区域作为Master,可进行本地读写。非Master区域的用户需要区分情况决定是本地读写还是跨区域读写。 全局共享数据:所有用户的行为都可以改变的数据,对一致性要求较高。处理:使用网络质量最好的机房存放数据,所有用户对全局共享数据的变更都被路由到这个机房。 3、消息层路由 异步调用时,如使用MQ进行调用,需要将消息路由到指定的机房。 ...

May 12, 2024

分布式锁高并发场景下的典型问题与优化实践

背景 开启课堂或者刷新课堂界面时会调用接口发送邀请链接公告,后台要限制一个课堂只能发送一次。 现象 同一个课堂出现了多条公告记录 解析 直接看代码,使用了分布式锁进行加锁校验,锁等待时间为0,也就是获取不到锁立刻返回。锁超时时间为课堂的超时时间,为12小时。 1、猜想一:发送公告有重试逻辑,有可能是重试逻辑有问题导致的。 在Google的接口调用中,使用动态代理进行接口的统一处理,如果调用Google接口返回了401状态码,就需要刷新AccessToken然后重新调用,如果刷新AccessToken失败就需要用户重新授权。 初步看代码逻辑没有问题,我们可以查看应用日志,如果是重试的问题导致的,那么这两次发送公告都应该是同一个请求,也就会是同一个TraceId,可以看到这两次发送成功是属于两个不同的请求,TraceId也是不一样的,那么可以排除这个猜想。 2、猜想二:锁没有生效,有并发问题。 我们使用 Jmeter 对这个接口进行压力测试,开启100个线程,结果是只有一个线程返回成功,其他线程都返回10304业务状态码,表示已经发送过公告了,而且始终没办法复现,返回成功状态码的请求始终只有一个。 3、猜想三:第一次获取锁成功了,后面删除了锁,所以第二次获取锁又成功了 查看Redis数据库也能看到锁对应的数据,TTL剩余9379秒,通过时间计算,可以得出这个Key的设置时间为9:49,跟第一次请求的时间是一致的,所以第二次获取锁的时候,这个锁是存在的。 4、猜想四:从以上的现象可以看出,这不是并发问题导致的,而且是属于不同的请求,两个请求基本没有什么关联,间隔也有8分钟左右。第二次获取锁的时候,锁的key也确实存在,确实是重复获取到了锁,那么基本确定只有一种可能,这是可重入锁,如果两个请求是同一个线程,那么就能重复获取到锁。查看应用日志,可以发现这两个请求确实属于同一个线程。 验证猜想:将Tomcat的工作线程数设置为1,这样每次请求都会是同一个请求,结果是每次请求都发送成功。 那么压力测试为什么复现不了这个问题呢,原因是压力测试时,100个请求基本同一时间发出,而Tomcat默认的最大线程池数量为200个线程,所以这100个请求都属于不同的线程。 解决方案 方案一:自实现不可重入锁,使用 setnx 指令简单实现。 方案二:加一层校验,在加锁之前判断这个 Key 是否存在。 这两种方案都可以,选择一种即可。 附 分布式锁加锁流程图

January 15, 2023