性能优化,实践浅谈

当经历了无数的日日夜夜,朝九晚九,攻克了无数难关,终于将系统预定功能开发完成,通过测试,部署上线后。你是否会感觉志得意满,到达了人生巅峰,高唱无敌是多么寂寞。

现实情况是,如果你这个系统,业务没有做起来,没啥人用,huan则罢liao。如果有越来越多的人,持续使用。随着用户增多,业务数据增多,那系统一定会暴露一些性能问题。而对这些问题的优化解决,以及监测,往往需要比开发具体功能,更高更全面的技术素质及能力。

一、性能问题监控

锅叔云:性能问题是具有隐蔽性,服务器硬件性能良好不等于系统服务性能良好。这么说可能经验欠缺的同学难于理解。不就是系统慢么,用户会告诉我们啊? 我们有服务器监控啊,如果cpu,或者内存满了,会有监控报警啊?

首先,系统慢用户未必会告诉你,如果比你的竞品慢太多,用户会用脚投票。然后,如果你开发的系统在把硬件跑到瓶颈之前都快如闪电,请收下锅叔的膝盖-_-|| 。

常见的性能问题,往往是欠缺性能考虑引起的,响应巨慢的同时,硬件利用率可能5%不到,这类问题也是此次锅叔主要讨论的。

经验上来说,对于性能问题的监控预警是难于解决具体的性能问题的。实践中我们需要一些日常机制来筛查系统性能问题,避免病入膏肓。

数据库慢查询日志——是一个重要的监控途径,其中记录了耗时较长的数据库操作记录。可以通过手动或自动分析慢查询日志,筛查可能存在的性能问题,主流数据库都支持慢查询日志生成,具体的配置方式此处不做赘述。非统计类的数据操作通常应该在100ms以下。

接口性能监控——后台系统通常是通过服务接口向外提供服务的,前端页面或者移动设备是通过调用服务端接口来完成对应操作的。接口的粒度是大于数据库操作的,一个接口调用可能包含很多个数据库调用。接口性能更接近于用户体验,因为多数时候用户的一个操作动作会对应一个服务接口(如保存,确认)。在不存在慢查询的时候,接口性能可能也会不满足要求,可能的原因如,一个接口循环调用了1000次数据库操作,或者调用了一些第三方接口等。对接口的性能监测原理上就是用调用结束的时间减去进入的时间点计算总耗时,并把这个耗时记录下来,以便时候筛查。Spring的切片能力可以方便的实现该需求。非报表,导出类接口,锅叔认为应当在1秒内完成为佳。

消息队列——如果你的系统中使用到了类似消息队列的机制,对队列中排队的消息数,同样应当进行监测,消息如果发生了堆积,说明在这个阶段内,系统的整体消费能力已经不能满足输入要求了。

以上三个监控维度是互不重叠的,应该同时进行。

二、性能问题的定位

除了数据库慢查询日志可以明确提示具体SQL缓慢外,上面另外两种情况所能直接提示定位到的粒度都比较大,对应一个接口或者一段处理过程代码。

定位更细问题的具体方法也很容易想到,即 分段输出各阶段的耗时。如对于一个100行的方法,可以在第30,60,100,分别计算并日志输出这3段执行耗费的时间。重复进行,就最终可以定位到将问题所在。

性能问题的定位需要有一些性能常识,所谓性能常识即,通常做一件事情需要完成的时间,不用很准确,但量级要清楚。比如一次数据库操作,一般在数十毫秒,与内存的交互在纳秒或者微秒间,与第三方系统的接口可能在数百毫秒到几秒之间。有了这些经验我们才能够对耗时是否合理有个基本判断。比如对于一个50毫秒的数据库操作,循环100次就是5秒,已经很慢了,可以考虑是不是可以合并成一次批量操作。

三、应用性能优化方法

合并远程调用——根据经验,实践中因为循环进行数据库操作,或对第三方系统接口进行循环调用,是引起性能问题的非常非常常见的原因。对于此类问题的优化方式通常就是优化调用的方式,使用批量操作。例如,如果需要去数据库中查询锅叔近一年的打卡记录,可以用准确日期,查询365次,也可以用时间范围一次查询出365条,后面的方法肯定比前面的快很多。如果方法比较复杂,冗长,可以从中抽取所需的公共数据,进行统一的批量查询取出,放入内存备用,会比哪里用到哪里查要快很多。同样写入,修改操作,也尽量批量进行。

使用缓存——对于访问频率较高的数据,可以在内存中存储,利用内存存取要快于硬盘很多的特性,来进行访问加速。常见的场景如各种计数——锅叔的文章有多少次浏览之类。

多线程并行——通过多线程把串行修改为并行。例如与设备通信查询状态,逐个查询和并行同时向设备查询,后者要快得多。现实中多数的操作耗时是在IO上,因此多线程方式可以有效提高性能,避免”空”等。多线程并行需要注意做好线程同步。

四、数据库性能优化

数据库是一个现代系统都会依赖的组件,对他的性能问题解决也是开发人员需要掌握的。

增加索引——加索引,是数据库优化的首选方案。原理是利用空间换时间。现在存储的成本下降非常快,基本上可以做到常规业务数据查询都可以走索引。对于复杂的sql 有时需要分析下怎么加索引,可以通过执行计划来分析。

锁等待——数据库是有锁概念的,一个事务占有X锁未提交前,其他事务是不能够对该记录进行操作的,只能等待。未使用唯一索引的数据库写操作,可能会对全表加写锁,在提交前,全表记录无法操作。因此对数据库锁,应当有所认识,尽量晚上锁,尽快解锁,尽量小范围上锁。推论可得,实践中,如果是长事务,尽量把更新操作后移,把耗时的非事务性操作(如无依赖的第三方接口等),设法从事务中移除。

事务隔离级别——选择合适的事务隔离级别,事务隔离级别与数据库锁有关,如最严格的串行隔离级别,所有的事务将串行进行。广泛使用的数据库MYSQL,其默认隔离级别为 “可重复读”,但带来了间隙锁的限制,增加了锁抢占的概率。如无特别,可以根据实际情况调整为 “读提交”

中间结果——本质可以理解为数据库层次的缓存,如果一些结果从全量记录中计算数据量巨大,耗时必然很长。可以分批计算,存储中间结果。以加速数据取得。如计算锅叔家近一年的总支出,可以通过每笔记录加起来,也可以每个月算一次,这样只需要查询近12个月的支出加起来就可以啦。

Original: https://www.cnblogs.com/uncleguo/p/16106699.html
Author: 锅叔
Title: 性能优化,实践浅谈

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/617222/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Docker 环境 Nacos2 MySQL8

    本文介绍 docker 环境下安装并单机运行 Nacos2,使用 docker 环境下的 MySQL 8 存储数据。 1 拉取镜像 1.1 创建目录 在硬盘上创建 nacos 的有…

    Java 2023年6月16日
    055
  • 设计模式 14 模板模式

    模板模式(Template Pattern)属于 行为型模式 在生活中常常会遇到这样的情况,做某一件事情,有些步骤是固定的,有些步骤的变化的。 比如去医院看病, 挂号和 排队这两个…

    Java 2023年6月6日
    081
  • SpringBoot多数据源yaml配置

    1.配置多数据源 2.设置默认数据源 配置中的 primary: db1 , 即是指定默认使用的数据库 spring: datasource: dynamic: primary: …

    Java 2023年6月15日
    089
  • 01-Spring Security框架学习

    出现 java.lang.NoSuchMethodError: org.springframework.util.AntPathMatcher.setCaseSensitive(Z…

    Java 2023年6月10日
    078
  • Nginx简单快速搭建文件服务器

    前言 在之前的一篇博文中介绍了Nginx负载均衡的实现,本篇文章就简单介绍下如何用Nginx搭建一个文件服务器。 Nginx安装 在之前的一篇博文中已经讲述过了,这里就不在讲述了。…

    Java 2023年5月30日
    070
  • Spring-Cloud-Alibaba系列教程(一)Nacos初识

    前言 在 2020年即将开启SpringCloudAlibaba的专题,希望2020年共同学习进步。 学习资料 文档 Naco文档 程序猿DD Spring …

    Java 2023年6月10日
    0101
  • 使用 Java 操作 Redis

    Jedis Jedis 是一款使用 Java 操作 Redis 的工具,有点类似于 JDBC redis.clients jedis 2.9.0 // 创建 jedis 客户端对象…

    Java 2023年6月8日
    087
  • 油猴插件安装以及好用的脚本推荐

    现在浏览器不搞几个插件和IE浏览器有啥区别,因此今天推荐一下及其强力的油猴(Tampermonkey)插件。 一、Tampermonkey插件安装 想使用插件首先要安装插件,我这里…

    Java 2023年6月13日
    082
  • TCP/IP和UDP

    TCP/IP即传输控制/网络协议,是面向连接的协议,发送数据前要先建立连接(发送方和接收方的成对的两个之间必须建 立连接),TCP提供可靠的服务,也就是说,通过TCP连接传输的数据…

    Java 2023年6月13日
    079
  • 使用stream flatmap获取集合中对象多个同类型数据 收集为另一个集合

    目的 把list集合中对象里面的多个string类型数据放在一个集合中 测试类 import java.util.ArrayList; import java.util.Colle…

    Java 2023年6月8日
    080
  • 服务路由

    前言 本文基于Dubbo2.6.x版本,中文注释版源码已上传github:xiaoguyu/dubbo 今天,来聊点短的,服务路由 Router,本文讲的是路由的调用路径,不讲路由…

    Java 2023年6月16日
    0106
  • xhydra的基础使用

    console–xhydra 在Target-Single Target输入目标IP(单个) 而Target List是批量爆破 Port:对应端口 Protocol:…

    Java 2023年6月7日
    063
  • Springboot优雅参数校验,统一响应,异常处理

    1.统一响应 (1)统一状态码首先定义一个状态码接口,所有状态码都需要实现它 public interface StatusCode { public int getCode();…

    Java 2023年6月8日
    074
  • springboot之启动原理解析及源码阅读

    前言 SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏。所以这次博主就跟你们一起一步步揭开Spri…

    Java 2023年6月5日
    0120
  • SpringCloud最新组件介绍

    服务注册中心:Eureka:2018年Eureka2.x闭源,不再推荐使用Zookeeper:3年前的系统部分公司用zookeeper+dubbo做微服务,当然zookeeper也…

    Java 2023年5月30日
    0119
  • 数据库时间格式处理

    使用 DateUtil转换,这个还是比较常用的一种,下面贴代码(可以直接复制使用): /** * 日期工具类,注意导包import和package * StringUtils,Da…

    Java 2023年6月7日
    077
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球