成为工程师 - 如何提升系统写性能(下)

简介: 成为工程师 - 如何提升系统写性能(下)

今日内容




今天我们接着上一篇文章的内容。继续来讲如何提升【写性能】。


下面这张图是我们上次给出关于提升写性能的概览图:



打钩的部分是已经在上一篇文章说讲完了的。今天,我们把剩下来的四种方式给讲完。他们分别是【异步法】【批量插入】【文件法】和【缓存法】。


01使用优化 - 异步法


异步法,顾名思义就是:将同步的过程转换为异步的过程


这种转换的作用在于:将一个很长的同步过程拆成一个或多个步骤,通过类似消息管道进行串联。同时也利用消息管道的重发能力进行补偿。


一个标准的异步化过程如下图这样:



大家跟着这个图的序号看一遍,这个图中显示了两个过程:


第一个过程:将收到的请求写入queue中,然后返回成功。


第二个过程:从queue中消费消息,继而进行后面的写动作。


这里的核心是:使用queue来缓冲所有的写请求


但是这里有个问题。因为第一步已经返回了用户成功,但是queue中的消息可能存在丢失、溢出、消费过慢的问题。这就导致了用户看到的结果和实际情况不一致。



那我们要怎么解决这个问题呢?我们可以使用下图这种方案来进行优化。



一样,大家跟着这个图中的序号看一遍。这个图和上一个图的区别在于两点。


第一,引入了一个cache。当我们把消息写到消息管道中后,我们就用cache记录一下他的状态。然后在这个消息真正被消费时,从缓存中删除这个状态。


第二,用户的第一阶段动作做完后,返回用户受理状态,而非成功。


用户可以发起请求状态的查询。我们可以根据cache中的情况,给用户返回状态。cache中如果还有,就说明请求处理中,cache中如果没有,就说明请求处理完了。


一般来说,写入动作都会伴有单据的生成。如果你的单据查询量不大的话,也可以不用引入cache。收到用户的查询请求后,直接查询数据库中单据状态返回。


02使用优化 - 批量插入


顾名思义,批量插入的含义就是将原来多个动作一起执行。就像下图这样:



那批量为什么会快呢?很多人没有思考过这个问题。


你想,虽然是把多个请求放在一起请求。但传输的数据量并没有变少,数据库处理的数据也没有变少。为什么批量就变快了呢?


批量的变快的原因是:


第一,可以减少加锁的次数。本来1个请求加1次锁,现在100个请求加1次锁。


第二,批量更新往往可以用上数据库对批量数据操作的优化

那如何实现单笔变批量?


01内存聚合


第一种方式,我把它称之为内存聚合。我们来看下面这张图。



上图中,多个请求过来,写到内存的queue中。然后每个线程循环检查自己的状态。系统中有另一个模块,定时从queue中捞取批量请求一起执行。


这种方式看着很有设计感,但其实并不常用。


因为这种设计有一定的复杂度。并且“请求不释放”、“queue中消息不消费”、“反复轮询请求状态”都容易给系统带来问题。


我把这个方案放在这里,主要是和大家探讨一种技术设计思路,但并不推荐使用。不过话说回来,在操作系统中常能见到这样的设计,所以操作系统真的很厉害。


02流水聚合


流水聚合法简单说就是:将需要处理的请求先入库,然后再批量捞取执行


我们看下面这个图:



这个图中,我们先把请求的流水落库,然后通过定时任务捞取所有的流水,并在内存中统一计算结果,然后更新数据库,标记原流水状态,结束。


敏感的同学一定已经发现,这个方案中也使用了异步的思想。只是在异步的思想上又叠加了批量处理的思想。


这种方案最大的好处就是:写流水是不锁库。但劣势就是:数据更新较慢,会有时延


但这里有个问题,如果写入请求的并发量实在太大了。DB就是写请求也扛不住,怎么办呢?


03使用优化 - 文件法


如果数据库扛不住写入请求,那就换个思路,不用DB了,咱们直接写文件。


文件法和批量流水本质一样,都是使用异步的思路。也分为上下两个阶段。


我们先看第一个阶段:写文件



一阶段做的事情非常简单,就是将请求进来的内容记录到文件中。


接下来我们看二阶段。二阶段其实也非常简单,就像下图这样。



二阶段就是:定时任务起来,服务去读取日志信息,然后执行写入动作


但这里有个问题。如果文件实在太大的话,这样的执行方式非常的低效。你想,用文件的方式就说明数据量一定小不了。


所以,我们更典型的方式会使用如下这种:



大家务必跟着我的序号来看


第一阶段,会有拆分服务去读取大文件,并把它拆分成小文件存储到分布式文件系统上。然后把分片文件的写入地址等塞到queue里去。


第二阶段,写入服务从queue里读取文件信息,然后处理一个一个小文件。解析其中的内容,并写到数据库里去。


这里的重点是:第一个阶段只能由单个线程去拆文件,以防止文件拆重。第二个阶段则可以用很多的服务器去一起捞取分片文件处理,以此来提高处理速度


这是大厂处理文件的典型方式。熟悉大数据解决方的同学一定也会觉得很熟悉。没错,hadoop也是这么处理大文件解析的。


这背后,其实是使用了经典的【分而治之】的思想。


04使用优化 - 缓存法


在上一篇文章中我有提到,写性能比读性能难的原因之一是:不能使用缓存。这是我故意留下的一个“错误”。


今天我们提到,缓存中间件也配有持久化方案。只是他的持久化方案不能保证数据完全安全。

但是,我们所有的场景都需要保证数据一点都不能丢吗?


如果有场景可以容忍一定程度的数据丢失,那缓存来当做数据库使用其实是可以的。比如点赞数、弹幕数、播放数、在线人数等这样的计数类需求。


这类需求往往请求量可能很大,但可以容忍在极端情况下有一小部分计数值的丢失。


那既然是把缓存当做DB来用。我们就要看看怎么来做持久化。


持久化的作用主要有两种:一个是故障的恢复,另一个是数据保存


对于“故障恢复”来说,如果没有特别的要求,可以就依赖缓存中间件自己提供的能力。

对于“数据保存”来说,如果你有这个容量,持续放在缓存中也是可以的,但如果缓存容量不够,一些较冷的数据想放在硬盘上。你就需要定时的去把缓存数据刷到数据库中,并且在需要的时候再实时刷进缓存。


下面是一张整体的示意图:



05性能小结


到这里,我们把读写性能都讲完了。


我们讲了很多的内容,但比这些内容更重要的是背后的设计思想。在这里我就和大家一起再来梳理一下。


我们直接来看下面我画的这张图。



【避免重复计算】重复的活儿不重复干,用空间换时间。

【减少无谓步骤】只为重要的事情付出时间。

【避免过程阻塞】能不等就不等,异步是个宝。

【引入更多资源】找人来干活,死磕不是办法。

【数据职责分离】只供读还是只供写,供全局还是供局部。

【合理技术选型】审时度势,先做选择。

【配合产品方案】产研是一家,问题一起扛。


今日小结


今天我们继续讲了【写性能】的提升方式。其中包括:“使用异步的方式”、“使用批量的方式”、“使用文件的方式”以及“使用缓存的方式”。

相关文章
|
2月前
|
监控 安全
Fantom 语言在公司监控电脑编程中的性能考量
在数字化办公环境中,公司对电脑监控的需求日益增长。Fantom 语言作为一种新兴的编程语言,具备简洁高效的语法结构,适用于构建公司电脑监控系统。其面向对象和函数式编程特性,使得代码易于管理和扩展。Fantom 在内存管理方面的独特优势有助于降低资源占用,提高响应速度,并且易于添加新功能。然而,实际应用中需根据具体需求和硬件环境不断优化,确保监控系统的稳定性和安全性。
27 3
|
3月前
|
存储 缓存 NoSQL
成为工程师 - 如何提升系统写性能(上)
成为工程师 - 如何提升系统写性能(上)
|
3月前
|
缓存 负载均衡 网络协议
成为工程师 - 如何提高系统的扩展性?
成为工程师 - 如何提高系统的扩展性?
|
3月前
|
缓存 NoSQL 算法
成为工程师 - 如何提升系统读性能(上)
成为工程师 - 如何提升系统读性能(上)
|
3月前
|
缓存 运维 监控
成为工程师 - 如何提升系统稳定性(1)
成为工程师 - 如何提升系统稳定性(1)
|
3月前
|
缓存 前端开发 数据库
成为工程师 - 如何提升系统读性能(下)
成为工程师 - 如何提升系统读性能(下)
|
3月前
|
消息中间件 缓存 Java
如何优化大型Java后端系统的性能:从代码到架构
当面对大型Java后端系统时,性能优化不仅仅是简单地提高代码效率或硬件资源的投入,而是涉及到多层次的技术策略。本篇文章将从代码层面的优化到系统架构的调整,详细探讨如何通过多种方式来提升Java后端系统的性能。通过对常见问题的深入分析和实际案例的分享,我们将探索有效的性能优化策略,帮助开发者构建更高效、更可靠的后端系统。
|
4月前
|
Java 大数据 测试技术
开发与运维测试问题之UseCompactObjectHeaders在SPECjbb2015基准测试中的表现如何解决
开发与运维测试问题之UseCompactObjectHeaders在SPECjbb2015基准测试中的表现如何解决
201 1
|
4月前
|
开发工具 UED git
如何应对LabVIEW工程师离职后的程序维护与优化
如何应对LabVIEW工程师离职后的程序维护与优化
38 0
|
6月前
|
搜索推荐
分享5款对工作学习有帮助的效率软件
今天再来推荐5个超级好用的效率软件,无论是对你的学习还是办公都能有所帮助,每个都堪称神器中的神器,用完后觉得不好用你找我。
52 6