在高并发的场景下,异步 是一个极其重要的优化方向。
前段时间,生产环境产生一次事变,笔者认为事变的场景十分具备 典型性。
写这篇文章,笔者想和大家深入探讨该场景的架构优化计划。心愿大家读完之后,能够对 异步 有更粗浅的了解。
1 业务场景
老师登录教研平台,会看到课程列表,点击课程后,课程会以视频的模式展示进去。
拜访课程详情页面,蕴含两个外围动作:
-
读取课程视频信息 :
从缓存服务器 Redis 获取课程的视频信息,返回给前端,前端通过视频组件渲染。
-
写入课程观看行为记录 :
当老师观看视频的过程中,浏览器每隔 3 秒发动申请,教研服务将观看行为记录插入到数据库表中。而且随着用户在线人数越多,写操作的频率也会指数级增长。
上线初期,这种设计运行还算良好,但随着在线用户的增多,零碎响应越来越慢,大量线程阻塞在写入视频观看进度表上的 Dao 办法。上。
首先咱们会想到一个十分直观的计划,晋升写入数据库的能力。
- 优化 SQL 语句;
- 晋升 MySQL 数据库硬件配置 ;
- 分库分表。
这种计划其实也能够满足咱们的需要,然而通过扩容硬件并不便宜,另外写操作能够容许适当提早和失落大量数据,那这种计划更显得性价比有余。
那么架构优化的方向应该是:“缩小写动作的耗时,晋升写动作的并发度”,只有这样能力让零碎更顺畅的运行。
于是,咱们想到了第二种计划:写申请异步化。
- 线程池模式
- 本地内存 + 定时工作
- MQ 模式
- Agent 服务 + MQ 模式
2 线程池模式
2014 年,笔者在艺龙旅行网负责红包零碎相干工作。经营零碎会调用红包零碎给特定用户发送红包,当这些用户登录 app 后,app 端会调用红包零碎的激活红包接口。
激活红包接口是一个写操作,速度也比拟快(20 毫秒左右),接口的日申请量在 2000 万左右。
利用拜访高峰期,红包零碎会变得不稳固,激活接口常常超时,笔者为了疾速解决问题,采取了一个十分毛糙的计划:
“控制器收到申请后,将写操作放入到独立的线程池中后,立刻返回给前端,而线程池会异步执行激活红包办法“。
坦白的讲,这是一个十分无效的计划,优化后,红包零碎十分稳固。
回到教研的场景,见下图,咱们也能够设计相似线程池模型的计划:
应用线程池模式,须要留神如下几点:
- 线程数不宜过高,防止占用过多的数据库连接池 ;
- 须要思考评估线程池队列的大小,免得呈现内存溢出的问题。
3 本地内存 + 定时工作
开源中国统计浏览数的计划十分经典。
用户拜访过一次文章、新闻、代码详情页面,拜访次数字段加 1 , 在 oschina 上这个操作是异步的,拜访的时候只是将数据在内存中保留,每隔固定工夫将这些数据写入数据库。
示例代码如下:
咱们能够借鉴开源中国的计划:
- 控制器接收申请后,观看进度信息存储到本地内存 LinkedBlockingQueue 对象里;
- 异步线程每隔 1 分钟从队列里获取数据,组装成 List 对象,最初调用 Jdbc batchUpdate 办法批量写入数据库;
- 批量写入次要是为了晋升零碎的整体吞吐量,每次批量写入的 List 大小也不宜过大。
这种计划长处是:不改变原有业务架构,简略易用,性能也高。该计划同样须要思考内存溢出的危险。
4 MQ 模式
很多同学们会想到 MQ 模式,音讯队列最外围的性能是 异步 和解耦,MQ 模式架构清晰,易于扩大。
外围流程如下:
- 控制器接收写申请,将观看视频行为记录转换成音讯;
- 教研服务发送音讯到 MQ,将写操作胜利信息返回给前端;
- 消费者服务从 MQ 中获取音讯,批量操作数据库。
这种计划长处是:
- MQ 自身反对高可用和异步,发送音讯效率高 , 也反对批量生产;
- 音讯在 MQ 服务端会长久化,可靠性要比保留在本地内存高;
不过 MQ 模式须要引入新的组件,减少额定的复杂度。
5 Agent 服务 + MQ 模式
互联网大厂还有一种常见的 异步 的计划:Agent 服务 + MQ 模式。
教研服务器上部署 Agent 服务(独立的过程), 教研服务接管写申请后,将申请依照固定的格局(比方 JSON)写入到本次磁盘中,而后给前端返回胜利信息。
Agent 服务会监听文件变动,将文件内容发送到音讯队列 , 消费者服务获取观看行为记录,将其存储到 MySQL 数据库中。
还有一种演进,假如咱们不想在利用中依赖音讯队列,不生成本地文件,能够采纳如下的形式:
这种计划最大的长处是:架构分层清晰,业务服务不须要引入 MQ 组件。
笔者原来接触过的性能监控平台,或者日志剖析平台都应用这种模式。
6 总结
学习须要一层一层递进的思考。
第一层:什么场景下须要异步
- 大量写操作占用了过多的资源,影响了零碎的失常运行;
- 写操作异步后,不影响主流程,容许适当提早;
第二层:异步的外功心法
本文提到了四种异步形式:
- 线程池模式
- 本地内存 + 定时工作
- MQ 模式
- Agent 服务 + MQ 模式
它们的独特特点是:将写操作命令存储在一个池子后,立即响应给前端,缩小写动作的耗时。工作服务异步从池子里获取工作后执行。
第三层:异步的实质
在笔者看来,异步是更细粒度的应用系统资源的一种形式。
在教研课程详情场景里,数据库的资源是固定的,但写操作占据大量数据库资源,导致整个零碎的阻塞,但写操作并不是最外围的业务流程,它不应该占用那么多的系统资源。
咱们应用异步的解决方案时,无论是应用线程池,还是本地内存 + 定时工作,亦或是 MQ,对数据库资源的应用都须要在正当的范畴内,只有这样零碎能力顺畅的运行。
如果我的文章对你有所帮忙,还请帮忙 点赞、在看、转发 一下,你的反对会激励我输入更高质量的文章,非常感谢!