菜单

老七云运管002
发布于 2023-03-03 / 0 阅读 / 0 评论 / 0 点赞

Web系统性能速度优化五部曲

Web系统性能速度优化五部曲

  • 其实无论做什么系统,性能和速度的优化无非是,在同一时间尽可能多的去处理业务逻辑,其中起到作用较高的,不外乎,多线程,缓存,消息中间件,下面就为大家介绍一下常见的五中优化方式。

1. 异步线程

工作几年后发现,只要想提高程序的性能,就绕不开多线程。最常见的场景,就是利用多线程并发执行多个局部事件,缩短总体完成时间。开发中,通常整个项目注册一个线程池的 Bean,各个方法都基于这个线程池来拿线程执行业务,容易针对线程池做参数调优。

有返回参数的异步,可以试试 CompletableFuture,也是 jdk8 提供的神器,比传统的 Feature 要好用,用法参考 CompletableFuture 教程。例如:当接口需要从多个外部系统取数据时,都可以异步执行,然后统一收集返回值。甚至利用 CompletableFuture 中特性,自动执行回调方法。

但要注意,也不是什么时候都要用异步:

  • 机器 CPU 资源有限:单台机器 CPU 的核心数有限,当多线程并发数达到顶点时,再加线程,反倒适得其反。此时可以考虑负载均衡,将并发线程分摊到多台机器上。

  • 同步更快:有些程序原本执行就很快,加了异步后反而慢了,毕竟分配线程资源也是需要时间的。例如总共只有十几条数据,流运算时不用 stream,而是 parallelStream

2. 缓存中间件

Redis

Redis 是最常用的缓存中间件了,它支持的常用数据结构挺多,要根据实际应用场景来选择,目前常用的有String、Hash、Set、List。

原始数据当然落在关系数据库中,但业务上常用的,通常是经过转化的中间数据。例如:员工登录后所属部门、角色权限、积分等数据,来自于不同的微服务,不能每次要用都调各方服务的接口,这些都需要缓存起来。

用缓存很无脑,但刷新缓存才是难题。像刚刚的例子,不能把所有的缓存数据都落到员工的粒度上,要根据业务来分层。例如:机构级别的数据,就每个机构存一份,按照员工所属机构来查;部门级别的数据,就每个部门存一份,按照员工所属部门来查。等等。

Elastic Search

用 ES 做缓存?估计很多人是大大的问号,谁让 Redis 当时不支持 Json 呢。从关系型数据库抽离出来的数据有时比较复杂,例如:人员所属的部门、角色、岗位等,每一个属性往下,背后的数据都不少。有人说 Redis 缓存个部门ID、角色ID,剩下的根据ID查表。但这些可是基础数据,且不说会不会把数据库查出问题,如果想要根据部门属性、角色属性、岗位属性来查人员,这个SQL该咋写。

最好的方式就是将这些数据从关系数据库中抽出来,以 Json 文档的形式缓存下来,MongoDB、ES 都能干这事。但为了应对后续可能千奇百怪的查询场景,还是 ES 保险一些。

可 ES 毕竟不是专业的缓存中间件,我很看好最近新出来的 RedisJson。完全满足日常工作需求,而且据说查询性能是 ES 的上百倍。

3. 消息中间件

这里不说 MQ 的其他特性,就聊优化性能吧。前面说单台机器的 CPU 资源有限,可以考虑将并发线程分摊到多台机器上,具体怎么做呢?

将需要处理任务通过消息投递到 MQ 中,消费者监听到 MQ 的消息后实际执行。倘若有1000个任务,单台机器能处理任务的最大并发线程数是100,那么10台机器就够了。

4. 减少系统交互

内存运算是最快的,要尽量减少和外部系统的交互次数。

例如:在查询一批数据时,每条数据需要通过外键,查询匹配的其他系统信息。如果其他系统信息种类不多的话,是不是通过查一次SQL或调用一次接口,一次性全拿过来。然后写代码做数据拼接。而不是遍历出每条数据,都去外部系统查一遍。

还有一些插入 MySQL、Redis 的一批数据,或给 MQ 发一批消息的,如果可以的话,就在程序内部处理好,然后调用批量插入、发送的方法,性能绝对能省不少。

5. Jvm 调优

jvm调优常见手段

  1. 堆内存监控 空间大小分配(年轻代、年老代、持久代分配)

    有了堆信息查看方面的功能,我们一般可以顺利解决以下问题:

    1. 年老代年轻代大小划分是否合理

    2. 内存泄漏

    3. 垃圾回收算法设置是否合理

  2. 线程监控 (线程信息监控:系统线程数量。线程状态监控:各个线程都处在什么样的状态下)

    热点分析

    1. CPU热点:检查系统哪些方法占用的大量CPU时间

    2. 内存热点:检查哪些对象在系统中数量最大(一定时间内存活对象和销毁对象一起统计)

  3. 快照

    快照是系统运行到某一时刻的一个定格。在我们进行调优的时候,不可能用眼睛去跟踪所有系统变化,依赖快照功能,我们就可以进行系统两个不同运行时刻,对象(或类、线程等)的不同,以便快速找到问题

    举例说,我要检查系统进行垃圾回收以后,是否还有该收回的对象被遗漏下来的了。那么,我可以在进行垃圾回收前后,分别进行一次堆情况的快照,然后对比两次快照的对象情况。

  4. 内存泄漏检查

    内存泄漏是比较常见的问题,而且解决方法也比较通用,这里可以重点说一下,而线程、热点方面的问题则是具体问题具体分析了。

    内存泄漏一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而导致新的资源分配请求无法完成,引起系统错误。

    内存泄漏对系统危害比较大,因为他可以直接导致系统的崩溃。

    需要区别一下,内存泄漏和系统超负荷两者是有区别的,虽然可能导致的最终结果是一样的。内存泄漏是用完的资源没有回收引起错误,而系统超负荷则是系统确实没有那么多资源可以分配了(其他的资源都在使用)。

文章转载自:https://www.l7y.cn/


评论