乐趣区

关于高并发:一次线上事故我顿悟了异步的精髓

在高并发的场景下,异步 是一个极其重要的优化方向。

前段时间,生产环境产生一次事变,笔者认为事变的场景十分具备 典型性

写这篇文章,笔者想和大家深入探讨该场景的架构优化计划。心愿大家读完之后,能够对 异步 有更粗浅的了解。

1 业务场景

老师登录教研平台,会看到课程列表,点击课程后,课程会以视频的模式展示进去。

拜访课程详情页面,蕴含两个外围动作:

  1. 读取课程视频信息 :

    从缓存服务器 Redis 获取课程的视频信息,返回给前端,前端通过视频组件渲染。

  2. 写入课程观看行为记录 :

    当老师观看视频的过程中,浏览器每隔 3 秒发动申请,教研服务将观看行为记录插入到数据库表中。而且随着用户在线人数越多,写操作的频率也会指数级增长。

上线初期,这种设计运行还算良好,但随着在线用户的增多,零碎响应越来越慢,大量线程阻塞在写入视频观看进度表上的 Dao 办法。上。

首先咱们会想到一个十分直观的计划,晋升写入数据库的能力

  1. 优化 SQL 语句;
  2. 晋升 MySQL 数据库硬件配置 ;
  3. 分库分表。

这种计划其实也能够满足咱们的需要,然而通过扩容硬件并不便宜,另外写操作能够容许适当提早和失落大量数据,那这种计划更显得性价比有余。

那么架构优化的方向应该是:“缩小写动作的耗时,晋升写动作的并发度”,只有这样能力让零碎更顺畅的运行。

于是,咱们想到了第二种计划:写申请异步化

  • 线程池模式
  • 本地内存 + 定时工作
  • MQ 模式
  • Agent 服务 + MQ 模式

2 线程池模式

2014 年,笔者在艺龙旅行网负责红包零碎相干工作。经营零碎会调用红包零碎给特定用户发送红包,当这些用户登录 app 后,app 端会调用红包零碎的激活红包接口。

激活红包接口是一个写操作,速度也比拟快(20 毫秒左右),接口的日申请量在 2000 万左右。

利用拜访高峰期,红包零碎会变得不稳固,激活接口常常超时,笔者为了疾速解决问题,采取了一个十分毛糙的计划:

控制器收到申请后,将写操作放入到独立的线程池中后,立刻返回给前端,而线程池会异步执行激活红包办法“。

坦白的讲,这是一个十分无效的计划,优化后,红包零碎十分稳固。

回到教研的场景,见下图,咱们也能够设计相似线程池模型的计划:

应用线程池模式,须要留神如下几点:

  1. 线程数不宜过高,防止占用过多的数据库连接池 ;
  2. 须要思考评估线程池队列的大小,免得呈现内存溢出的问题。

3 本地内存 + 定时工作

开源中国统计浏览数的计划十分经典。

用户拜访过一次文章、新闻、代码详情页面,拜访次数字段加 1 , 在 oschina 上这个操作是异步的,拜访的时候只是将数据在内存中保留,每隔固定工夫将这些数据写入数据库。

示例代码如下:

咱们能够借鉴开源中国的计划:

  1. 控制器接收申请后,观看进度信息存储到本地内存 LinkedBlockingQueue 对象里;
  2. 异步线程每隔 1 分钟从队列里获取数据,组装成 List 对象,最初调用 Jdbc batchUpdate 办法批量写入数据库;
  3. 批量写入次要是为了晋升零碎的整体吞吐量,每次批量写入的 List 大小也不宜过大。

这种计划长处是:不改变原有业务架构,简略易用,性能也高。该计划同样须要思考内存溢出的危险。

4 MQ 模式

很多同学们会想到 MQ 模式,音讯队列最外围的性能是 异步 解耦,MQ 模式架构清晰,易于扩大。

外围流程如下:

  1. 控制器接收写申请,将观看视频行为记录转换成音讯;
  2. 教研服务发送音讯到 MQ,将写操作胜利信息返回给前端;
  3. 消费者服务从 MQ 中获取音讯,批量操作数据库。

这种计划长处是:

  1. MQ 自身反对高可用和异步,发送音讯效率高 , 也反对批量生产;
  2. 音讯在 MQ 服务端会长久化,可靠性要比保留在本地内存高;

不过 MQ 模式须要引入新的组件,减少额定的复杂度。

5 Agent 服务 + MQ 模式

互联网大厂还有一种常见的 异步 的计划:Agent 服务 + MQ 模式。

教研服务器上部署 Agent 服务(独立的过程), 教研服务接管写申请后,将申请依照固定的格局(比方 JSON)写入到本次磁盘中,而后给前端返回胜利信息。

Agent 服务会监听文件变动,将文件内容发送到音讯队列 , 消费者服务获取观看行为记录,将其存储到 MySQL 数据库中。

还有一种演进,假如咱们不想在利用中依赖音讯队列,不生成本地文件,能够采纳如下的形式:

这种计划最大的长处是:架构分层清晰,业务服务不须要引入 MQ 组件。

笔者原来接触过的性能监控平台,或者日志剖析平台都应用这种模式。

6 总结

学习须要一层一层递进的思考。

第一层:什么场景下须要异步

  • 大量写操作占用了过多的资源,影响了零碎的失常运行;
  • 写操作异步后,不影响主流程,容许适当提早;

第二层:异步的外功心法

本文提到了四种异步形式:

  • 线程池模式
  • 本地内存 + 定时工作
  • MQ 模式
  • Agent 服务 + MQ 模式

它们的独特特点是:将写操作命令存储在一个池子后,立即响应给前端,缩小写动作的耗时。工作服务异步从池子里获取工作后执行。

第三层:异步的实质

在笔者看来,异步是更细粒度的应用系统资源的一种形式

在教研课程详情场景里,数据库的资源是固定的,但写操作占据大量数据库资源,导致整个零碎的阻塞,但写操作并不是最外围的业务流程,它不应该占用那么多的系统资源。

咱们应用异步的解决方案时,无论是应用线程池,还是本地内存 + 定时工作,亦或是 MQ,对数据库资源的应用都须要在正当的范畴内,只有这样零碎能力顺畅的运行。


如果我的文章对你有所帮忙,还请帮忙 点赞、在看、转发 一下,你的反对会激励我输入更高质量的文章,非常感谢!

退出移动版