大数跨境
0
0

SpringBoot服务性能优化

SpringBoot服务性能优化 二进制跳动
2021-02-05
6
导读:SpringBoot服务性能优化

Prometheus(普罗米修斯),它是一个是时序数据库,能够存储我们的指标。SpringBoot 可以非常方便地接入到 Prometheus 中。

SpringBoot 如何开启监控?

创建一个 SpringBoot 项目后,首先加入 maven 依赖。

<dependency>     <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency>     <groupId>io.micrometer</groupId>     <artifactId>micrometer-registry-prometheus</artifactId> </dependency> <dependency>     <groupId>io.micrometer</groupId>     <artifactId>micrometer-core</artifactId> </dependency>
management.endpoint.metrics.enabled=truemanagement.endpoints.web.exposure.include=*management.endpoint.prometheus.enabled=truemanagement.metrics.export.prometheus.enabled=true

想要监控业务数据也是比较简单的,你只需要注入一个 MeterRegistry 实例即可,下面是一段示例代码:

@AutowiredMeterRegistry registry;@GetMapping("/test")@ResponseBodypublic String test() {    registry.counter("test",            "from""127.0.0.1",            "method""test"    ).increment();    return "ok";}

HTTP 优化

下面我们举例来看一下,哪些动作能够加快网页的获取。为了描述方便,我们仅讨论 HTTP1.1 协议的。

1.使用 CDN 加速文件获取

比较大的文件,尽量使用 CDN(Content Delivery Network)分发,甚至是一些常用的前端脚本、样式、图片等,都可以放到 CDN 上。CDN 通常能够加快这些文件的获取,网页加载也更加迅速。

2.合理设置 Cache-Control 值

浏览器会判断 HTTP 头 Cache-Control 的内容,用来决定是否使用浏览器缓存,这在管理一些静态文件的时候,非常有用,相同作用的头信息还有 Expires。Cache-Control 表示多久之后过期;Expires 则表示什么时候过期。

这个参数可以在 Nginx 的配置文件中进行设置。

location ~* ^.+\.(ico|gif|jpg|jpeg|png)$ {             # 缓存1年            add_header Cache-Control: no-cache, max-age=31536000;}

3.减少单页面请求域名的数量

减少每个页面请求的域名数量,尽量保证在 4 个之内。这是因为,浏览器每次访问后端的资源,都需要先查询一次 DNS,然后找到 DNS 对应的 IP 地址,再进行真正的调用。

DNS 有多层缓存,比如浏览器会缓存一份、本地主机会缓存、ISP 服务商缓存等。从 DNS 到 IP 地址的转变,通常会花费 20-120ms 的时间。减少域名的数量,可加快资源的获取。

4.开启 gzip

开启 gzip,可以先把内容压缩后,浏览器再进行解压。由于减少了传输的大小,会减少带宽的使用,提高传输效率。

在 nginx 中可以很容易地开启,配置如下:

gzip on;gzip_min_length 1k;gzip_buffers 4 16k;gzip_comp_level 6;gzip_http_version 1.1;gzip_types text/plain application/javascript text/css;

5.对资源进行压缩

对 JavaScript 和 CSS,甚至是 HTML 进行压缩。道理类似,现在流行的前后端分离模式,一般都是对这些资源进行压缩的。

6.使用 keepalive

由于连接的创建和关闭,都需要耗费资源。用户访问我们的服务后,后续也会有更多的互动,所以保持长连接可以显著减少网络交互,提高性能。

nginx 默认开启了对客户端的 keep alived 支持,你可以通过下面两个参数来调整它的行为。

http {    keepalive_timeout  120s 120s;    keepalive_requests 10000;}

Skywalking

对于一个 web 服务来说,最缓慢的地方就在于数据库操作。对于如何定位到复杂分布式环境中的问题,我这里想要分享另外一个工具:Skywalking。

Skywalking 是使用探针技术(JavaAgent)来实现的。通过在 Java 的启动参数中,加入 javaagent 的 Jar 包,即可将性能数据和调用链数据封装,并发送到 Skywalking 的服务器。



小年快乐鸭!


小年,并非专指一个日子,由于各地风俗,被称为“小年”的日子也不尽相同。


各个层次的优化方向

1.Controller 层

controller 层用于接收前端的查询参数,然后构造查询结果。现在很多项目都采用前后端分离的架构,所以 controller 层的方法,一般会使用 @ResponseBody 注解,把查询的结果,解析成 JSON 数据返回(兼顾效率和可读性)。

由于 controller 只是充当了一个类似功能组合和路由的角色,所以这部分对性能的影响就主要体现在数据集的大小上。如果结果集合非常大,JSON 解析组件就要花费较多的时间进行解析,

大结果集不仅会影响解析时间,还会造成内存浪费。

假如结果集在解析成 JSON 之前,占用的内存是 10MB,那么在解析过程中,有可能会使用 20M 或者更多的内存去做这个工作。

由于返回对象的嵌套层次太深、引用了不该引用的对象(比如非常大的 byte[] 对象),造成了内存使用的飙升。

所以,对于一般的服务,保持结果集的精简,是非常有必要的,这也是 DTO(data transfer object)存在的必要。如果你的项目,返回的结果结构比较复杂,对结果集进行一次转换是非常有必要的。

2.Service 层

service 层用于处理具体的业务,大部分功能需求都是在这里完成的。service 层一般是使用单例模式,很少会保存状态,而且可以被 controller 复用。

service 层的代码组织,对代码的可读性、性能影响都比较大。我们常说的设计模式,大多数都是针对 service 层来说的。

service 层会频繁使用更底层的资源,通过组合的方式获取我们所需要的数据,

这里要着重提到的一点,就是分布式事务(简单提及,不做发散)。

关于传统事务和柔性事务,我们来简单比较一下。

ACID

关系数据库, 最大的特点就是事务处理, 即满足 ACID。

  • 原子性(Atomicity):事务中的操作要么都做,要么都不做。

  • 一致性(Consistency):系统必须始终处在强一致状态下。

  • 隔离性(Isolation):一个事务的执行不能被其他事务所干扰。

  • 持久性(Durability):一个已提交的事务对数据库中数据的改变是永久性的。

BASE

BASE 方法通过牺牲一致性和孤立性来提高可用性和系统性能。

BASE 为 Basically Available、Soft-state、Eventually consistent 三者的缩写,其中 BASE 分别代表:

  • 基本可用(Basically Available):系统能够基本运行、一直提供服务。

  • 软状态(Soft-state):系统不要求一直保持强一致状态。

  • 最终一致性(Eventual consistency):系统需要在某一时刻后达到一致性要求。

3.Dao 层

经过合理的数据缓存,我们都会尽量避免请求穿透到 Dao 层。除非你对 ORM 本身提供的缓存特性特别的熟悉;否则,都推荐你使用更加通用的方式去缓存数据。

Dao 层,主要在于对 ORM 框架的使用上。比如,在 JPA 中,如果加了一对多或者多对多的映射关系,而又没有开启懒加载,级联查询的时候就容易造成深层次的检索,造成了内存开销大、执行缓慢的后果。

在一些数据量比较大的业务中,多采用分库分表的方式。在这些分库分表组件中,很多简单的查询语句,都会被重新解析后分散到各个节点进行运算,最后进行结果合并。

举个例子,select count(*) from a 这句简单的 count 语句,就可能将请求路由到十几张表中去运算,最后在协调节点进行统计,执行效率是可想而知的。目前,分库分表中间件,比较有代表性的是驱动层的 ShardingJdbc 和代理层的 MyCat,它们都有这样的问题。这些组件提供给使用者的视图是一致的,但我们在编码的时候,一定要注意这些区别。







下面我们来总结一下。

本课时,我们简单看了一下 SpringBoot 常见的优化思路,然后介绍了三个新的性能分析工具。

  • 一个是监控系统 Prometheus,可以看到一些具体的指标大小;

  • 一个是 Skywalking,可以分析分布式环境中的调用链。

SpringBoot 自身的 Web 容器是 Tomcat,那我们就可以通过对 Tomcat 的调优来获取性能提升。当然,对于服务上层的负载均衡 Nginx,我们也提供了一系列的优化思路。

最后,我们看了在经典的 MVC 架构下,Controller、Service、Dao 的一些优化方向,并着重看了 Service 层的分布式事务问题。

SpringBoot 作为一个广泛应用的服务框架,在性能优化方面已经做了很多工作,选用了很多高速组件。比如,数据库连接池默认使用 hikaricp,Redis 缓存框架默认使用 lettuce,本地缓存提供 caffeine 等。对于一个普通的数据库交互的 Web 服务来说,缓存是最主要的优化手段。

【声明】内容源于网络
0
0
二进制跳动
15 年 + 技术老兵 架构师|技术总监|科技创业技术合伙人 曾任职苏宁科技、电讯盈科、联想云 专注架构设计与技术落地
内容 739
粉丝 0
二进制跳动 15 年 + 技术老兵 架构师|技术总监|科技创业技术合伙人 曾任职苏宁科技、电讯盈科、联想云 专注架构设计与技术落地
总阅读448
粉丝0
内容739