文章很長,而且持續更新,建議收藏起來,慢慢讀!瘋狂創客圈總目錄 博客園版 為您奉上珍貴的學習資源 :
免費贈送 :《尼恩Java面試寶典》 持續更新+ 史上最全 + 面試必備 2000頁+ 面試必備 + 大廠必備 +漲薪必備
免費贈送 經典圖書:《Java高並發核心編程(卷1)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 經典圖書:《Java高並發核心編程(卷2)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 經典圖書:《Java高並發核心編程(卷3)加強版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 經典圖書:《尼恩Java面試寶典 最新版》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
免費贈送 資源寶庫: Java 必備 百度網盤資源大合集 價值>10000元 加尼恩領取
Nginx實現10萬+並發
在優化內核時,可以做的事情很多,不過,我們通常會根據業務特點來進行調整,當Nginx作為靜態web內容服務器、反向代理或者提供壓縮服務器的服務器時,期內核參數的調整都是不同的,
概述
由於默認的linux內核參數考慮的是最通用場景,這明顯不符合用於支持高並發訪問的Web服務器的定義,所以需要修改Linux內核參數,讓Nginx可以擁有更高的性能;
參考關鍵的Linux內核優化參數
/etc/sysctl.conf
修改 /etc/sysctl.conf 來更改內核參數
修改好配置文件,執行 sysctl -p 命令,使配置立即生效
fs.file-max = 2024000
fs.nr_open = 1024000
net.ipv4.tcp_tw_reuse = 1
ner.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_rmem = 10240 87380 12582912
net.ipv4.tcp_wmem = 10240 87380 12582912
net.core.netdev_max_backlog = 8096
net.core.rmem_default = 6291456
net.core.wmem_default = 6291456
net.core.rmem_max = 12582912
net.core.wmem_max = 12582912
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_recycle = 1
net.core.somaxconn=262114
net.ipv4.tcp_max_orphans=262114
針對Nginx支持超高吞吐,需要優化的,主要是文件句柄數,TCP網絡參數:
系統最大可以打開的句柄數
fs.file-max = 2024000
將TIME_WAIT狀態的socket重新用於新的TCP鏈接
net.ipv4.tcp_tw_reuse = 1
#參數設置為 1 ,表示允許將TIME_WAIT狀態的socket重新用於新的TCP鏈接,這對於服務器來說意義重大,因為總有大量TIME_WAIT狀態的鏈接存在;
TCP發送keepalive消息的頻度
ner.ipv4.tcp_keepalive_time = 600
#當keepalive啟動時,TCP發送keepalive消息的頻度;
默認是2小時,將其設置為10分鍾,可以更快的清理無效鏈接。
socket保持在FIN_WAIT_2狀態的最大時間
net.ipv4.tcp_fin_timeout = 30
#當服務器主動關閉鏈接時,socket保持在FIN_WAIT_2狀態的最大時間
允許TIME_WAIT套接字數量的最大值
net.ipv4.tcp_max_tw_buckets = 5000
# 這個參數表示操作系統允許TIME_WAIT套接字數量的最大值,
# 如果超過這個數字,TIME_WAIT套接字將立刻被清除並打印警告信息。
# 該參數默認為180000,過多的TIME_WAIT套接字會使Web服務器變慢。
本地端口的取值范圍
net.ipv4.ip_local_port_range = 1024 65000
#定義UDP和TCP鏈接的本地端口的取值范圍。
每個Socket在Linux中都映射為一個文件,並與內核中兩個緩沖區(讀緩沖區、寫緩沖區)相關聯。或者說,每個Socket擁有兩個內核緩沖區。通過下面的四個選項配置
-
rmem_default:一個Socket的被創建出來時,默認的讀緩沖區大小,單位字節;
-
wmem_default:一個Socket的被創建出來時,默認的寫緩沖區大小,單位字節;
-
rmem_max:一個Socket的讀緩沖區可由程序設置的最大值,單位字節;
-
wmem_max:一個Socket的寫緩沖區可由程序設置的最大值,單位字節;
net.core.rmem_default = 6291456
#表示內核套接字接受緩存區默認大小。
net.core.wmem_default = 6291456
#表示內核套接字發送緩存區默認大小。
net.core.rmem_max = 12582912
#表示內核套接字接受緩存區最大大小。
net.core.wmem_max = 12582912
#表示內核套接字發送緩存區最大大小。
注意:以上的四個參數,需要根據業務邏輯和實際的硬件成本來綜合考慮;
還有兩個參數,tcp_rmem、tcp_wmem。為每個TCP連接分配的讀、寫緩沖區內存大小,單位是Byte
tcp_rmem接受緩存的最小值、默認值、最大值
net.ipv4.tcp_rmem = 10240 87380 12582912
#定義了TCP接受緩存的最小值、默認值、最大值。
第一個數字表示緩沖區最小值,為TCP連接分配的最小內存,默認為pagesize(4K字節),每一個socket接收窗口大小下限;
第二個數字表示緩沖區的默認值,為TCP連接分配的缺省內存,默認值為16K,為接收窗口大小,所謂的窗口大小只是一個限制數值,實際對應的內存緩沖區由協議棧管理分配;
第三個數字表示緩沖區的最大值,為TCP連接分配的最大內存,每個socket鏈路接收窗口大小上限,用於tcp協議棧自動調整窗口大小的上限。
注意:實際對應的內存緩沖區由協議棧管理分配
一般按照缺省值分配,上面的例子最新為10KB,默認86KB
發送緩存的最小值、默認值、最大值。
net.ipv4.tcp_wmem = 10240 87380 12582912
#定義TCP發送緩存的最小值、默認值、最大值。
以上是TCP socket的讀寫緩沖區的設置,每一項里面都有三個值:
- 第一個值是緩沖區最小值
- 中間值是緩沖區的默認值
- 最后一個是緩沖區的最大值
net.core與net.ipv4開頭的區別
net.core開頭的配置為網絡層通用配置,net.ipv4開頭的配置為ipv4使用網絡配置。
雖然ipv4緩沖區的值不受core緩沖區的值的限制,但是緩沖區的最大值仍舊受限於core的最大值。
net.core.netdev_max_backlog = 8096
#當網卡接收數據包的速度大於內核處理速度時,會有一個列隊保存這些數據包。這個參數表示該列隊的最大值。
TCP socket緩沖區大小是他自己控制而不是由core內核緩沖區控制。
TCP發送緩沖區和接收緩沖區的模型如下:
Client 創建一個 TCP 的 socket,並通過 SO_SNDBUF 選項設置它的發送緩沖區大小為 4096 字節,連接到 Server 后,每 1 秒發送一個 TCP 數據段長度為 1024 的報文。Server 端不調用 recv()。預期的結果分為以下幾個階段:
Phase 1 Server 端的 socket 接收緩沖區未滿,所以盡管 Server 不會 recv(),但依然能對 Client 發出的報文回復 ACK;
Phase 2 Server 端的 socket 接收緩沖區被填滿了,向 Client 端通告零窗口(Zero Window)。Client 端待發送的數據開始累積在 socket 的發送緩沖區;
Phase 3 Client 端的 socket 的發送緩沖區滿了,用戶進程阻塞在 send() 上。
用於解決TCP的SYN攻擊
net.ipv4.tcp_syncookies = 1
#與性能無關。用於解決TCP的SYN攻擊。
接受SYN請求列隊的最大長度
net.ipv4.tcp_max_syn_backlog = 8192
#這個參數表示TCP三次握手建立階段接受SYN請求列隊的最大長度,默認1024,
# 將其設置的大一些
# 可以使出現Nginx繁忙來不及accept新連接的情況時,Linux不至於丟失客戶端發起的鏈接請求。
啟用timewait快速回收
net.ipv4.tcp_tw_recycle = 1
#這個參數用於設置啟用timewait快速回收。
調節系統同時發起的TCP連接數
net.core.somaxconn=262114
# 選項默認值是128,
# 這個參數用於調節系統同時發起的TCP連接數,
# 在高並發的請求中,默認的值可能會導致鏈接超時或者重傳,因此需要結合高並發請求數來調節此值。
防止簡單的DOS攻擊
net.ipv4.tcp_max_orphans=262114
# 選項用於設定系統中最多有多少個TCP套接字不被關聯到任何一個用戶文件句柄上。
# 如果超過這個數字,孤立鏈接將立即被復位並輸出警告信息。
# 這個限制只是為了防止簡單的DOS攻擊,
# 不用過分依靠這個限制甚至認為的減小這個值,更多的情況是增加這個值。
單進程的文件句柄數配置
/etc/security/limits.conf
/etc/security/limits.conf
* soft nofile 1024000
* hard nofile 1024000
* soft nproc 655360
* hard nproc 655360
* soft stack unlimited
* hard stack unlimited
* soft memlock unlimited
* hard memlock unlimited
進程最大打開文件描述符數
* soft nofile 1000000
* hard nofile 1000000
* soft nproc 655360
* hard nproc 655360
# *代表針對所有用戶
# nproc 是代表最大進程數
# nofile 是代表最大文件打開數
hard和soft的區別:在設定上,通常soft會比hard小,
舉例來說,soft可以設置為80,而hard設定為100,那么你可以使用到90(沒有超過100),但介於80~100之間時,系統會有警告信息通知你。
總之:
a. 所有進程打開的文件描述符數不能超過/proc/sys/fs/file-max
b. 單個進程打開的文件描述符數不能超過user limit中nofile的soft limit
c. nofile的soft limit不能超過其hard limit
d. nofile的hard limit不能超過/proc/sys/fs/nr_open
RocketMQ生產環境配置
參考的broker 配置
集群架構為異步刷盤、同步復制
#請修改
brokerClusterName=XXXCluster
brokerName=broker-a
brokerId=0
listenPort=10911
#請修改
namesrvAddr=x.x.x.x:9876;x.x.x.x::9876
defaultTopicQueueNums=4
autoCreateTopicEnable=false
autoCreateSubscriptionGroup=false
deleteWhen=04
fileReservedTime=48
mapedFileSizeCommitLog=1073741824
mapedFileSizeConsumeQueue=50000000
destroyMapedFileIntervalForcibly=120000
redeleteHangedFileInterval=120000
diskMaxUsedSpaceRatio=88
#存儲路徑
storePathRootDir=/data/rocketmq/store
#commitLog存儲路徑
storePathCommitLog=/data/rocketmq/store/commitlog
#消費隊列存儲路徑
storePathConsumeQueue=/data/rocketmq/store/consumequeue
# 消息索引存儲路徑
storePathIndex=/data/rocketmq/store/index
# checkpoint 文件存儲路徑
storeCheckpoint=/data/rocketmq/store/checkpoint
#abort 文件存儲路徑
abortFile=/data/rocketmq/store/abort
maxMessageSize=65536
flushCommitLogLeastPages=4
flushConsumeQueueLeastPages=2
flushCommitLogThoroughInterval=10000
flushConsumeQueueThoroughInterval=60000
brokerRole=SYNC_MASTER
flushDiskType=ASYNC_FLUSH
checkTransactionMessageEnable=false
maxTransferCountOnMessageInMemory=1000
transientStorePoolEnable=true
warmMapedFileEnable=true
pullMessageThreadPoolNums=128
slaveReadEnable=true
transferMsgByHeap=false
waitTimeMillsInSendQueue=1000
ElasticSearch生產環境配置
參考的配置文件
/etc/sysctl.conf
fs.file-max = 2024000
fs.nr_open = 1024000
net.ipv4.tcp_tw_reuse = 1
ner.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_rmem = 10240 87380 12582912
net.ipv4.tcp_wmem = 10240 87380 12582912
net.core.netdev_max_backlog = 8096
net.core.rmem_default = 6291456
net.core.wmem_default = 6291456
net.core.rmem_max = 12582912
net.core.wmem_max = 12582912
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_recycle = 1
net.core.somaxconn=262114
net.ipv4.tcp_max_orphans=262114
net.ipv4.tcp_retries2 = 5
vm.max_map_count = 262144
操作系統
較大的文件描述符
Lucene使用了非常大量的文件。 並且Elasticsearch使用大量的套接字在節點和HTTP客戶端之間進行通信。
所有這些都需要可用的文件描述符。
可悲的是,許多現代的Linux發行版每個進程允許一個不允許的1024個文件描述符。
這對於一個小的Elasticsearch節點來說太低了,更不用說處理數百個索引的節點了。
設置MMap
Elasticsearch還針對各種文件使用NioFS和MMapFS的混合。
確保配置最大映射計數,以便有足夠的虛擬內存可用於mmapped文件。
Elasticsearch默認使用一個mappfs目錄來存儲索引。默認操作系統對mmap計數的限制可能太低,這可能會導致內存不足異常。
暫時設置 sysctl -w vm.max_map_count=262144
永久設置
$ vim /etc/sysctl.conf
# 設置操作系統mmap數限制,Elasticsearch與Lucene使用mmap來映射部分索引到Elasticsearch的地址空間
# 為了讓mmap生效,Elasticsearch還需要有創建需要內存映射區的能力。最大map數檢查是確保內核允許創建至少262144個內存映射區
vm.max_map_count = 262144
JVM虛擬機
除非Elasticsearch網站上另有說明,否則應始終運行最新版本的Java虛擬機(JVM)。
Elasticsearch和Lucene都是比較苛刻的軟件。
Lucene的單元和集成測試通常暴露JVM本身的錯誤。
Number of threads(線程數或者進程數)
Elasticsearch為不同類型的操作使用了許多線程池。它能夠在需要時創建新線程,這一點很重要。確保Elasticsearch用戶可以創建的線程數量至少是4096個。
$ vim /etc/security/limits.conf
elasticsearch soft nproc 4096
elasticsearch hard nproc 4096
給lucene留下一半的內存空間
一個常見的問題是配置一個太大的堆。你有一個64GB的機器,並且你想給Elasticsearch所有64GB的內存。
更多更好?!堆對Elasticsearch絕對重要,它被許多內存數據結構使用以提供快速操作。
但是還有另一個主要的內存用戶是 Lucene。Lucene旨在利用底層操作系統來緩存內存中的數據結構。
Lucene的segment 段存儲在單獨的文件中,因為段是不可變的,所以這些文件從不改變。這使得它們非常易於緩存,並且底層操作系統將適合的保持segment駐留在內存中以便更快地訪問。
這些段包括反向索引(用於全文搜索)和docvalues(用於聚合)。
Lucene的性能依賴於與操作系統的這種交互。但是如果你給Elasticsearch的堆提供所有可用的內存,Lucene就不會有任何剩余的內存。
這會嚴重影響性能。
標准建議是給Elasticsearch堆提供50%的可用內存,同時保留其他50%的空閑內存。
它不會不使用; Lucene會愉快地吞噬剩下的任何東西。
如果你不是聚合在分析的字符串字段(例如你不需要fielddata),你可以考慮降低堆更多。你可以做的堆越小,你可以期望從
Elasticsearch(更快的GC)和Lucene(更多的內存緩存)更好的性能。
不要超過32G
事實證明,當堆大小小於32GB時,HotSpot JVM使用一個技巧來壓縮對象指針。
可以通過-XX:+PrintFlagsFinal來查看,在es2.2.0后不用設置,啟動后會打印compressed ordinary object pointers [true]
在Java中,所有對象都在堆上分配並由指針引用。
Ordinary object pointers(OOP)指向這些對象,並且通常是CPU本地字的大小:32位或64位,取決於處理器。
指針引用值的確切字節位置。 對於32位系統,這最大堆大小為4GB。
對於64位系統,堆大小可以變得更大,但64位指針的開銷意味着更多的浪費空間,因為指針更大。並且比浪費的空間更糟,當在主存儲器和各種高速緩存(LLC,L1等)之間移動值時,較大的指針占用更多的帶寬。
Java使用一個名為compress oops的技巧來解決這個問題。指針不是指向存儲器中的精確字節位置,而是引用對象偏移。這意味着32位指針可以引用四十億個對象,而不是40億字節。
最終,這意味着堆可以增長到大約32 GB的物理大小,同時仍然使用32位指針。
一旦你超越32GB邊界,指針切換回Ordinary object pointers。
每個指針的大小增加,使用更多的CPU內存帶寬,並且您有效地丟失了內存。
事實上,它需要直到大約40到50GB的分配的堆,你有一個堆的相同有效內存剛剛低於32GB使用壓縮oops。所以即使你有內存,盡量避免跨越32 GB堆邊界。它浪費內存,降低CPU性能,並使GC與大堆爭奪。
swapping是性能的死穴
它應該是顯而易見的,但它明確拼寫出來:將主內存交換到磁盤會破壞服務器性能。 內存中操作是需要快速執行的操作。如果內存交換到磁盤,100微秒操作將花費10毫秒。 現在重復所有其他10us操作的延遲增加。 不難看出為什么交換對於性能來說是可怕的。
1、最好的辦法是在系統上完全禁用交換。 這可以臨時完成:
sudo swapoff -a
要永久禁用則需要編輯/etc/fstab。請查閱操作系統的文檔。
2、如果完全禁用交換不是一個選項,您可以嘗試
sysctl vm.swappiness = 1
(查看cat /proc/sys/vm/swappiness)
這個設置控制操作系統如何積極地嘗試交換內存。 以防止在正常情況下交換,但仍然允許操作系統在緊急情況下交換。swappiness值1比0好,因為在一些內核版本上,swappiness為0可以調用OOM-killer。
3、最后,如果兩種方法都不可能,就應該啟用mlockall。 這允許JVM鎖定其內存,並防止它被操作系統交換。 可以在elasticsearch.yml中設置:
bootstrap.mlockall: true
TCP retransmission timeout(TCP重傳超時)
集群中的每一對節點通過許多TCP連接進行通信,這些TCP連接一直保持打開狀態,直到其中一個節點關閉或由於底層基礎設施中的故障而中斷節點之間的通信。
TCP通過對通信應用程序隱藏臨時的網絡中斷,在偶爾不可靠的網絡上提供可靠的通信。在通知發送者任何問題之前,您的操作系統將多次重新傳輸任何丟失的消息。大多數Linux發行版默認重傳任何丟失的數據包15次。重傳速度呈指數級下降,所以這15次重傳需要900秒才能完成。這意味着Linux使用這種方法需要花費許多分鍾來檢測網絡分區或故障節點。Windows默認只有5次重傳,相當於6秒左右的超時。
Linux默認允許在可能經歷很長時間包丟失的網絡上進行通信,但是對於單個數據中心內的生產網絡來說,這個默認值太大了,就像大多數Elasticsearch集群一樣。高可用集群必須能夠快速檢測節點故障,以便它們能夠通過重新分配丟失的碎片、重新路由搜索以及可能選擇一個新的主節點來迅速作出反應。因此,Linux用戶應該減少TCP重傳的最大數量。
$ vim /etc/sysctl.conf
net.ipv4.tcp_retries2 = 5
config/ jvm.options
- Elasticsearch有足夠的可用堆是非常重要的。
- 堆的最小值(Xms)與堆的最大值(Xmx)設置成相同的。
- Elasticsearch的可用堆越大,它能在內存中緩存的數據越多。但是需要注意堆越大在垃圾回收時造成的暫停會越長。
- 設置Xmx不要大於物理內存的50%。用來確保有足夠多的物理內存預留給操作系統緩存。
- 禁止用串行收集器來運行Elasticsearch(-XX:+UseSerialGC),默認JVM配置通過Elasticsearch的配置將使用CMS回收器。
-Xms32g
-Xmx32g
硬件方面
內存
首先最重要的資源是內存,排序和聚合都可能導致內存匱乏,因此足夠的堆空間來容納這些是重要的。
即使堆比較小,也要給操作系統高速緩存提供額外的內存,因為Lucene使用的許多數據結構是基於磁盤的格式,Elasticsearch利用操作系統緩存有很大的影響。
64GB RAM的機器是最理想的,但32GB和16GB機器也很常見。
少於8GB往往適得其反(你最終需要許多,許多小機器),大於64GB可能會有問題,我們將在討論在堆:大小和交換。
CPU
大多數Elasticsearch部署往往對CPU要求很不大。因此,確切的處理器設置比其他資源更重要,應該選擇具有多個內核的現代處理器。通用集群使用2到8核機器。
如果需要在較快的CPU或更多核之間進行選擇,請選擇更多核。 多核提供的額外並發將遠遠超過稍快的時鍾速度。
硬盤
磁盤對於所有集群都很重要,尤其是對於索引很重的集群(例如攝取日志數據的磁盤)。 磁盤是服務器中最慢的子系統,這意味着大量寫入的群集可以輕松地飽和其磁盤,這反過來成為群集的瓶頸。
如果你能買得起SSD,他們遠遠優於任何旋轉磁盤。 支持SSD的節點看到查詢和索引性能方面的提升。
如果使用旋轉磁盤,請嘗試獲取盡可能最快的磁盤(高性能服務器磁盤,15k轉速驅動器)。
使用RAID 0是提高磁盤速度的有效方法,適用於旋轉磁盤和SSD。 沒有必要使用RAID的鏡像或奇偶校驗變體,因為高可用性是通過副本建立到Elasticsearch中。
最后,避免網絡連接存儲(NAS)。 NAS通常較慢,顯示較大的延遲,平均延遲的偏差較大,並且是單點故障。
網絡
快速和可靠的網絡對於分布式系統中的性能顯然是重要的。低延遲有助於確保節點可以輕松地進行通信,而高帶寬有助於分段移動和恢復。現代數據中心網絡(1GbE,10GbE)對於絕大多數集群都是足夠的。
避免跨越多個數據中心的群集,即使數據中心位置非常接近。絕對避免跨越大地理距離的集群。
Elasticsearch集群假定所有節點相等,而不是一半的節點距離另一個數據中心中有150ms。較大的延遲往往會加劇分布式系統中的問題,並使調試和解決更加困難。
與NAS參數類似,每個人都聲稱數據中心之間的管道是穩健的和低延遲。(吹牛)。從我們的經驗,管理跨數據中心集群的麻煩就是浪費成本。
其他配置
現在可以獲得真正巨大的機器如數百GB的RAM和幾十個CPU內核。 另外也可以在雲平台(如EC2)中啟動數千個小型虛擬機。 哪種方法最好?
一般來說,最好選擇中到大盒子。 避免使用小型機器,因為您不想管理具有一千個節點的集群,而簡單運行Elasticsearch的開銷在這種小型機器上更為明顯。
同時,避免真正巨大的機器。 它們通常導致資源使用不平衡(例如,所有內存正在使用,但沒有CPU),並且如果您必須為每台機器運行多個節點,可能會增加后期的運維復雜性。