日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
非常哇塞的SpringBoot性能優(yōu)化長(zhǎng)文!

本文將詳細(xì)講解SpringBoot服務(wù)優(yōu)化的一般思路,并附上若干篇輔助文章作為開(kāi)胃菜。

專(zhuān)注于為中小企業(yè)提供成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)望花免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

本文較長(zhǎng),最適合收藏之。

一.有監(jiān)控才有方向

在開(kāi)始對(duì)SpringBoot服務(wù)進(jìn)行性能優(yōu)化之前,我們需要做一些準(zhǔn)備,把SpringBoot服務(wù)的一些數(shù)據(jù)暴露出來(lái)。

比如,你的服務(wù)用到了緩存,就需要把緩存命中率這些數(shù)據(jù)進(jìn)行收集;用到了數(shù)據(jù)庫(kù)連接池,就需要把連接池的參數(shù)給暴露出來(lái)。

我們這里采用的監(jiān)控工具是Prometheus,它是一個(gè)是時(shí)序數(shù)據(jù)庫(kù),能夠存儲(chǔ)我們的指標(biāo)。SpringBoot可以非常方便的接入到Prometheus中。

創(chuàng)建一個(gè)SpringBoot項(xiàng)目后,首先,加入maven依賴(lài)。


org.springframework.boot
spring-boot-starter-actuator


io.micrometer
micrometer-registry-prometheus


io.micrometer
micrometer-core

然后,我們需要在application.properties配置文件中,開(kāi)放相關(guān)的監(jiān)控接口。

management.endpoint.metrics.enabled=true
management.endpoints.web.exposure.include=*
management.endpoint.prometheus.enabled=true
management.metrics.export.prometheus.enabled=true

啟動(dòng)之后,我們就可以通過(guò)訪(fǎng)問(wèn) http://localhost:8080/actuator/prometheus 來(lái)獲取監(jiān)控?cái)?shù)據(jù)。

想要監(jiān)控業(yè)務(wù)數(shù)據(jù)也是比較簡(jiǎn)單的。你只需要注入一個(gè)MeterRegistry實(shí)例即可。下面是一段示例代碼:

@Autowired
MeterRegistry registry;
@GetMapping("/test")
@ResponseBody
public String test() {
registry.counter("test",
"from", "127.0.0.1",
"method", "test"
).increment();
return "ok";
}

從監(jiān)控連接中,我們可以找到剛剛添加的監(jiān)控信息。

test_total{from="127.0.0.1",method="test",} 5.0

這里簡(jiǎn)單介紹一下流行的Prometheus監(jiān)控體系,Prometheus使用拉的方式獲取監(jiān)控?cái)?shù)據(jù),這個(gè)暴露數(shù)據(jù)的過(guò)程可以交給功能更加齊全的telegraf組件。

如圖,我們通常使用Grafana進(jìn)行監(jiān)控?cái)?shù)據(jù)的展示,使用AlertManager組件進(jìn)行提前預(yù)警。這一部分的搭建工作不是我們的重點(diǎn),感興趣的同學(xué)可自行研究。下圖便是一張典型的監(jiān)控圖,可以看到Redis的緩存命中率等情況。

二.Java生成火焰圖

火焰圖是用來(lái)分析程序運(yùn)行瓶頸的工具。在縱向,表示的是調(diào)用棧的深度;橫向表明的是消耗的時(shí)間。所以格子的寬度越大,越說(shuō)明它可能是一個(gè)瓶頸。

火焰圖也可以用來(lái)分析Java應(yīng)用??梢詮膅ithub上下載async-profiler的壓縮包 進(jìn)行相關(guān)操作。

比如,我們把它解壓到/root/目錄。然后以javaagent的方式來(lái)啟動(dòng)Java應(yīng)用。命令行如下:

java -agentpath:/root/build/libasyncProfiler.so=start,svg,file=profile.svg -jar spring-petclinic-2.3.1.BUILD-SNAPSHOT.jar

運(yùn)行一段時(shí)間后,停止進(jìn)程,可以看到在當(dāng)前目錄下,生成了profile.svg文件,這個(gè)文件是可以用瀏覽器打開(kāi)的,一層層向下瀏覽,即可找到需要優(yōu)化的目標(biāo)。

三.Skywalking

對(duì)于一個(gè)web服務(wù)來(lái)說(shuō),最緩慢的地方就在于數(shù)據(jù)庫(kù)操作。所以,使用本地緩存和分布式緩存優(yōu)化,能夠獲得最大的性能提升。

對(duì)于如何定位到復(fù)雜分布式環(huán)境中的問(wèn)題,我這里想要分享另外一個(gè)工具:Skywalking。

Skywalking是使用探針技術(shù)(JavaAgent)來(lái)實(shí)現(xiàn)的。通過(guò)在Java的啟動(dòng)參數(shù)中,加入javaagent的Jar包,即可將性能數(shù)據(jù)和調(diào)用鏈數(shù)據(jù)封裝、發(fā)送到Skywalking的服務(wù)器。

下載相應(yīng)的安裝包(如果使用ES存儲(chǔ),需要下載專(zhuān)用的安裝包),配置好存儲(chǔ)之后,即可一鍵啟動(dòng)。

將agent的壓縮包,解壓到相應(yīng)的目錄。

tar xvf skywalking-agent.tar.gz  -C /opt/

在業(yè)務(wù)啟動(dòng)參數(shù)中加入agent的包。比如,原來(lái)的啟動(dòng)命令是:

java  -jar /opt/test-service/spring-boot-demo.jar  --spring.profiles.active=dev

改造后的啟動(dòng)命令是:

java -javaagent:/opt/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=the-demo-name  -jar /opt/test-service/spring-boot-demo.ja  --spring.profiles.active=dev

訪(fǎng)問(wèn)一些服務(wù)的鏈接,打開(kāi)Skywalking的UI,即可看到下圖的界面。我們可以從圖中找到響應(yīng)比較慢QPS又比較高的的接口,進(jìn)行專(zhuān)項(xiàng)優(yōu)化。

15723404104715

四.優(yōu)化思路

對(duì)一個(gè)普通的Web服務(wù)來(lái)說(shuō),我們來(lái)看一下,要訪(fǎng)問(wèn)到具體的數(shù)據(jù),都要經(jīng)歷哪些主要的環(huán)節(jié)。

如下圖,在瀏覽器中輸入相應(yīng)的域名,需要通過(guò)DNS解析到具體的IP地址上。為了保證高可用,我們的服務(wù)一般都會(huì)部署多份,然后使用Nginx做反向代理和負(fù)載均衡。

Nginx根據(jù)資源的特性,會(huì)承擔(dān)一部分動(dòng)靜分離的功能。其中,動(dòng)態(tài)功能部分,會(huì)進(jìn)入我們的SpringBoot服務(wù)。

SpringBoot默認(rèn)使用內(nèi)嵌的tomcat作為Web容器,使用典型的MVC模式,最終訪(fǎng)問(wèn)到我們的數(shù)據(jù)。

五.HTTP優(yōu)化

下面我們舉例來(lái)看一下,哪些動(dòng)作能夠加快網(wǎng)頁(yè)的獲取。為了描述方便,我們僅討論HTTP1.1協(xié)議的。

1.使用CDN加速文件獲取

比較大的文件,盡量使用CDN(Content Delivery Network)分發(fā)。甚至是一些常用的前端腳本、樣式、圖片等,都可以放到CDN上。CDN通常能夠加快這些文件的獲取,網(wǎng)頁(yè)加載也更加迅速。

2.合理設(shè)置Cache-Control值

瀏覽器會(huì)判斷HTTP頭Cache-Control的內(nèi)容,用來(lái)決定是否使用瀏覽器緩存,這在管理一些靜態(tài)文件的時(shí)候,非常有用。相同作用的頭信息還有Expires。Cache-Control表示多久之后過(guò)期,Expires則表示什么時(shí)候過(guò)期。

這個(gè)參數(shù)可以在Nginx的配置文件中進(jìn)行設(shè)置。

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

3.減少單頁(yè)面請(qǐng)求域名的數(shù)量

減少每個(gè)頁(yè)面請(qǐng)求的域名數(shù)量,盡量保證在4個(gè)之內(nèi)。這是因?yàn)椋瑸g覽器每次訪(fǎng)問(wèn)后端的資源,都需要先查詢(xún)一次DNS,然后找到DNS對(duì)應(yīng)的IP地址,再進(jìn)行真正的調(diào)用。

DNS有多層緩存,比如瀏覽器會(huì)緩存一份、本地主機(jī)會(huì)緩存、ISP服務(wù)商緩存等。從DNS到IP地址的轉(zhuǎn)變,通常會(huì)花費(fèi)20-120ms的時(shí)間。減少域名的數(shù)量,可加快資源的獲取。

4.開(kāi)啟gzip

開(kāi)啟gzip,可以先把內(nèi)容壓縮后,瀏覽器再進(jìn)行解壓。由于減少了傳輸?shù)拇笮?,?huì)減少帶寬的使用,提高傳輸效率。

在nginx中可以很容易的開(kāi)啟。配置如下:

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.對(duì)資源進(jìn)行壓縮

對(duì)JavaScript和CSS,甚至是HTML進(jìn)行壓縮。道理類(lèi)似,現(xiàn)在流行的前后端分離模式,一般都是對(duì)這些資源進(jìn)行壓縮的。

6.使用keepalive

由于連接的創(chuàng)建和關(guān)閉,都需要耗費(fèi)資源。用戶(hù)訪(fǎng)問(wèn)我們的服務(wù)后,后續(xù)也會(huì)有更多的互動(dòng),所以保持長(zhǎng)連接可以顯著減少網(wǎng)絡(luò)交互,提高性能。

nginx默認(rèn)開(kāi)啟了對(duì)客戶(hù)端的keep avlide支持。你可以通過(guò)下面兩個(gè)參數(shù)來(lái)調(diào)整它的行為。

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

nginx與后端upstream的長(zhǎng)連接,需要手工開(kāi)啟,參考配置如下:

location ~ /{  
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}

六.Tomcat優(yōu)化

Tomcat本身的優(yōu)化,也是非常重要的一環(huán)??梢灾苯訁⒖枷旅娴奈恼隆?/p>

搞定tomcat重要參數(shù)調(diào)優(yōu)!

七.自定義Web容器

如果你的項(xiàng)目并發(fā)量比較高,想要修改最大線(xiàn)程數(shù)、最大連接數(shù)等配置信息,可以通過(guò)自定義Web容器的方式,代碼如下所示。

@SpringBootApplication(proxyBeanMethods = false)
public class App implements WebServerFactoryCustomizer {
public static void main(String[] args) {
SpringApplication.run(PetClinicApplication.class, args);
}
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
TomcatServletWebServerFactory f = (TomcatServletWebServerFactory) factory;
f.setProtocol("org.apache.coyote.http11.Http11Nio2Protocol");
f.addConnectorCustomizers(c -> {
Http11NioProtocol protocol = (Http11NioProtocol) c.getProtocolHandler();
protocol.setMaxConnections(200);
protocol.setMaxThreads(200);
protocol.setSelectorTimeout(3000);
protocol.setSessionTimeout(3000);
protocol.setConnectionTimeout(3000);
});
}
}

注意上面的代碼,我們?cè)O(shè)置了它的協(xié)議為org.apache.coyote.http11.Http11Nio2Protocol,意思就是開(kāi)啟了Nio2。這個(gè)參數(shù)在Tomcat8.0之后才有,開(kāi)啟之后會(huì)增加一部分性能。對(duì)比如下:

默認(rèn)。

8080/owners?lastName=
Running 30s test @ http://172.16.1.57:8080/owners?lastName=
2 threads and 100 connections
Thread calibration: mean lat.: 4588.131ms, rate sampling interval: 16277ms
Thread calibration: mean lat.: 4647.927ms, rate sampling interval: 16285ms
Thread Stats Avg Stdev Max +/- Stdev
Latency 16.49s 4.98s 27.34s 63.90%
Req/Sec 106.50 1.50 108.00 100.00%
6471 requests in 30.03s, 39.31MB read
Socket errors: connect 0, read 0, write 0, timeout 60
Requests/sec: 215.51
Transfer/sec: 1.31MB

Nio2。

[root@localhost wrk2-master]# ./wrk -t2 -c100 -d30s -R2000 http://172.16.1.57:8080/owners?lastName=
Running 30s test @ http://172.16.1.57:8080/owners?lastName=
2 threads and 100 connections
Thread calibration: mean lat.: 4358.805ms, rate sampling interval: 15835ms
Thread calibration: mean lat.: 4622.087ms, rate sampling interval: 16293ms
Thread Stats Avg Stdev Max +/- Stdev
Latency 17.47s 4.98s 26.90s 57.69%
Req/Sec 125.50 2.50 128.00 100.00%
7469 requests in 30.04s, 45.38MB read
Socket errors: connect 0, read 0, write 0, timeout 4
Requests/sec: 248.64
Transfer/sec: 1.51MB

你甚至可以將tomcat替換成undertow。undertow也是一個(gè)Web容器,更加輕量級(jí)一些,占用的內(nèi)容更少,啟動(dòng)的守護(hù)進(jìn)程也更少,更改方式如下:


org.springframework.boot
spring-boot-starter-web


org.springframework.boot
spring-boot-starter-tomcat




org.springframework.boot
spring-boot-starter-undertow

八.各個(gè)層次的優(yōu)化方向

Controller層

controller層用于接收前端的查詢(xún)參數(shù),然后構(gòu)造查詢(xún)結(jié)果?,F(xiàn)在很多項(xiàng)目都采用前后端分離的架構(gòu),所以controller層的方法,一般會(huì)使用@ResponseBody注解,把查詢(xún)的結(jié)果,解析成JSON數(shù)據(jù)返回(兼顧效率和可讀性)。

由于controller只是充當(dāng)了一個(gè)類(lèi)似功能組合和路由的角色,所以這部分對(duì)性能的影響就主要體現(xiàn)在數(shù)據(jù)集的大小上。如果結(jié)果集合非常大,JSON解析組件就要花費(fèi)較多的時(shí)間進(jìn)行解析。

大結(jié)果集不僅會(huì)影響解析時(shí)間,還會(huì)造成內(nèi)存浪費(fèi)。假如結(jié)果集在解析成JSON之前,占用的內(nèi)存是10MB,那么在解析過(guò)程中,有可能會(huì)使用20M或者更多的內(nèi)存去做這個(gè)工作。我見(jiàn)過(guò)很多案例,由于返回對(duì)象的嵌套層次太深、引用了不該引用的對(duì)象(比如非常大的byte[]對(duì)象),造成了內(nèi)存使用的飆升。

所以,對(duì)于一般的服務(wù),保持結(jié)果集的精簡(jiǎn),是非常有必要的,這也是DTO(data transfer object)存在的必要。如果你的項(xiàng)目,返回的結(jié)果結(jié)構(gòu)比較復(fù)雜,對(duì)結(jié)果集進(jìn)行一次轉(zhuǎn)換是非常有必要的。

另外,可以使用異步Servlet對(duì)Controller層進(jìn)行優(yōu)化。它的原理如下:Servlet 接收到請(qǐng)求之后,將請(qǐng)求轉(zhuǎn)交給一個(gè)異步線(xiàn)程來(lái)執(zhí)行業(yè)務(wù)處理,線(xiàn)程本身返回至容器,異步線(xiàn)程處理完業(yè)務(wù)以后,可以直接生成響應(yīng)數(shù)據(jù),或者將請(qǐng)求繼續(xù)轉(zhuǎn)發(fā)給其它 Servlet。

Service層

service層用于處理具體的業(yè)務(wù),大部分功能需求都是在這里完成的。service層一般是使用單例模式(prototype),很少會(huì)保存狀態(tài),而且可以被controller復(fù)用。

service層的代碼組織,對(duì)代碼的可讀性、性能影響都比較大。我們常說(shuō)的設(shè)計(jì)模式,大多數(shù)都是針對(duì)于service層來(lái)說(shuō)的。

這里要著重提到的一點(diǎn),就是分布式事務(wù)。

如上圖,四個(gè)操作分散在三個(gè)不同的資源中。要想達(dá)到一致性,需要三個(gè)不同的資源進(jìn)行統(tǒng)一協(xié)調(diào)。它們底層的協(xié)議,以及實(shí)現(xiàn)方式,都是不一樣的。那就無(wú)法通過(guò)Spring提供的Transaction注解來(lái)解決,需要借助外部的組件來(lái)完成。

很多人都體驗(yàn)過(guò),加入了一些保證一致性的代碼,一壓測(cè),性能掉的驚掉下巴。分布式事務(wù)是性能殺手,因?yàn)樗褂妙~外的步驟去保證一致性,常用的方法有:兩階段提交方案、TCC、本地消息表、MQ事務(wù)消息、分布式事務(wù)中間件等。

如上圖,分布式事務(wù)要在改造成本、性能、實(shí)效等方面進(jìn)行綜合考慮。有一個(gè)介于分布式事務(wù)和非事務(wù)之間的名詞,叫做柔性事務(wù)。柔性事務(wù)的理念是將業(yè)務(wù)邏輯和互斥操作,從資源層上移至業(yè)務(wù)層面。

關(guān)于傳統(tǒng)事務(wù)和柔性事務(wù),我們來(lái)簡(jiǎn)單比較一下。

ACID

關(guān)系數(shù)據(jù)庫(kù), 最大的特點(diǎn)就是事務(wù)處理, 即滿(mǎn)足ACID。

  • 原子性(Atomicity):事務(wù)中的操作要么都做,要么都不做。
  • 一致性(Consistency):系統(tǒng)必須始終處在強(qiáng)一致?tīng)顟B(tài)下。
  • 隔離性(Isolation):一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)所干擾。
  • 持續(xù)性(Durability):一個(gè)已提交的事務(wù)對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變是永久性的。

BASE

BASE方法通過(guò)犧牲一致性和孤立性來(lái)提高可用性和系統(tǒng)性能。

BASE為Basically Available, Soft-state, Eventually consistent三者的縮寫(xiě),其中BASE分別代表:

  • 基本可用(Basically Available):系統(tǒng)能夠基本運(yùn)行、一直提供服務(wù)。
  • 軟狀態(tài)(Soft-state):系統(tǒng)不要求一直保持強(qiáng)一致?tīng)顟B(tài)。
  • 最終一致性(Eventual consistency):系統(tǒng)需要在某一時(shí)刻后達(dá)到一致性要求。

互聯(lián)網(wǎng)業(yè)務(wù),推薦使用補(bǔ)償事務(wù),完成最終一致性。比如,通過(guò)一系列的定時(shí)任務(wù),完成對(duì)數(shù)據(jù)的修復(fù)。具體可以參照下面的文章。

常用的 分布式事務(wù) 都有哪些?我該用哪個(gè)?

Dao層

經(jīng)過(guò)合理的數(shù)據(jù)緩存,我們都會(huì)盡量避免請(qǐng)求穿透到Dao層。除非你對(duì)ORM本身提供的緩存特性特別的熟悉,否則,都推薦你使用更加通用的方式去緩存數(shù)據(jù)。

Dao層,主要在于對(duì)ORM框架的使用上。比如,在JPA中,如果加了一對(duì)多或者多對(duì)多的映射關(guān)系,而又沒(méi)有開(kāi)啟懶加載,級(jí)聯(lián)查詢(xún)的時(shí)候就容易造成深層次的檢索,造成了內(nèi)存開(kāi)銷(xiāo)大、執(zhí)行緩慢的后果。

在一些數(shù)據(jù)量比較大的業(yè)務(wù)中,多采用分庫(kù)分表的方式。在這些分庫(kù)分表組件中,很多簡(jiǎn)單的查詢(xún)語(yǔ)句,都會(huì)被重新解析后分散到各個(gè)節(jié)點(diǎn)進(jìn)行運(yùn)算,最后進(jìn)行結(jié)果合并。

舉個(gè)例子,select count(*) from a這句簡(jiǎn)單的count語(yǔ)句,就可能將請(qǐng)求路由到十幾張表中去運(yùn)算,最后在協(xié)調(diào)節(jié)點(diǎn)進(jìn)行統(tǒng)計(jì),執(zhí)行效率是可想而知的。目前,分庫(kù)分表中間件,比較有代表性的是驅(qū)動(dòng)層的ShardingJdbc和代理層的MyCat,它們都有這樣的問(wèn)題。這些組件提供給使用者的視圖是一致的,但我們?cè)诰幋a的時(shí)候,一定要注意這些區(qū)別。

End

下面我們來(lái)總結(jié)一下。

我們簡(jiǎn)單看了一下SpringBoot常見(jiàn)的優(yōu)化思路。我們介紹了三個(gè)新的性能分析工具。一個(gè)是監(jiān)控系統(tǒng)Prometheus,可以看到一些具體的指標(biāo)大小;一個(gè)是火焰圖,可以看到具體的代碼熱點(diǎn);一個(gè)是Skywalking,可以分析分布式環(huán)境中的調(diào)用鏈。在對(duì)性能有疑惑的時(shí)候,我們都會(huì)采用類(lèi)似于神農(nóng)氏嘗百草的方式,綜合各種測(cè)評(píng)工具的結(jié)果進(jìn)行分析。

SpringBoot自身的Web容器是Tomcat,那我們就可以通過(guò)對(duì)Tomcat的調(diào)優(yōu)來(lái)獲取性能提升。當(dāng)然,對(duì)于服務(wù)上層的負(fù)載均衡Nginx,我們也提供了一系列的優(yōu)化思路。

最后,我們看了在經(jīng)典的MVC架構(gòu)下,Controller、Service、Dao的一些優(yōu)化方向,并著重看了Service層的分布式事務(wù)問(wèn)題。

這里有一個(gè)具體的優(yōu)化示例。

5秒到1秒,記一次效果“非常”顯著的性能優(yōu)化

SpringBoot作為一個(gè)廣泛應(yīng)用的服務(wù)框架,在性能優(yōu)化方面已經(jīng)做了很多工作,選用了很多高速組件。比如,數(shù)據(jù)庫(kù)連接池默認(rèn)使用hikaricp,Redis緩存框架默認(rèn)使用lettuce,本地緩存提供caffeine等。對(duì)于一個(gè)普通的于數(shù)據(jù)庫(kù)交互的Web服務(wù)來(lái)說(shuō),緩存是最主要的優(yōu)化手。但細(xì)節(jié)決定成敗,你要是想對(duì)系統(tǒng)做極致的優(yōu)化,還需要參考下面的這篇文章。

??卓越性能 の 庫(kù)(非廣告)


名稱(chēng)欄目:非常哇塞的SpringBoot性能優(yōu)化長(zhǎng)文!
本文URL:http://www.5511xx.com/article/dhishhc.html