一次线上事故,我顿悟了异步的精髓
The following article is from 勇哥java实战分享 Author 勇哥
在高并发的场景下,异步是一个极其重要的优化方向。
前段时间,生产环境发生一次事故,笔者认为事故的场景非常具备典型性 。
写这篇文章,笔者想和大家深入探讨该场景的架构优化方案。希望大家读完之后,可以对异步有更深刻的理解。
1 业务场景
老师登录教研平台,会看到课程列表,点击课程后,课程会以视频的形式展现出来。
优化 SQL 语句;
提升 MySQL 数据库硬件配置 ;
分库分表。
线程池模式
本地内存 + 定时任务
MQ 模式
Agent 服务 + MQ 模式
线程数不宜过高,避免占用过多的数据库连接 ;
需要考虑评估线程池队列的大小,以免出现内存溢出的问题。
控制器接收请求后,观看进度信息存储到本地内存 LinkedBlockingQueue 对象里;
异步线程每隔1分钟从队列里获取数据 ,组装成 List 对象,最后调用 Jdbc batchUpdate 方法批量写入数据库;
批量写入主要是为了提升系统的整体吞吐量,每次批量写入的 List 大小也不宜过大 。
控制器接收写请求,将观看视频行为记录转换成消息 ;
教研服务发送消息到 MQ ,将写操作成功信息返回给前端 ;
消费者服务从 MQ 中获取消息 ,批量操作数据库 。
MQ 本身支持高可用和异步,发送消息效率高 , 也支持批量消费;
消息在 MQ 服务端会持久化,可靠性要比保存在本地内存高;
大量写操作占用了过多的资源,影响了系统的正常运行;
写操作异步后,不影响主流程,允许适当延迟;
线程池模式
本地内存 + 定时任务
MQ 模式
Agent 服务 + MQ 模式
不能为了异步而异步,无论是使用线程池,还是本地内存 + 定时任务 ,亦或是 MQ ,对数据库资源的使用都需要在合理的范围内,否则异步就达不到我们想要的效果。
SpringBoot四大核心组件,你知道几个? ULID - 一种比UUID更好的方案,新特性! 如果你还在用Swagger(丝袜哥)生成接口文档,那就真有点老“土”了! 妙用Java 8中的 Function接口 消灭if...else(非常新颖的写法)