中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

網站開發(fā)的項目開發(fā)網站開發(fā)公司排行榜

網站開發(fā)的項目開發(fā),網站開發(fā)公司排行榜,做項目的招聘網站,網站建設周記通信框架功能設計 功能描述 通信框架承載了業(yè)務內部各模塊之間的消息交互和服務調用,它的主要功能如下: 基于 Netty 的 NIO 通信框架,提供高性能的異步通信能力; 提供消息的編解碼框架,可以實現 POJO 的序列化和反…

通信框架功能設計

功能描述

???????? 通信框架承載了業(yè)務內部各模塊之間的消息交互和服務調用,它的主要功能如下:
????????基于 Netty 的 NIO 通信框架,提供高性能的異步通信能力;
????????提供消息的編解碼框架,可以實現 POJO 的序列化和反序列化;
????????消息內容的防篡改機制
????????提供基于 IP 地址的白名單接入認證機制;
????????鏈路的有效性校驗機制;
????????鏈路的斷連重連機制

通信模型

(1)客戶端發(fā)送應用握手請求消息,攜帶節(jié)點 ID 等有效身份認證信息;
(2)服務端對應用握手請求消息進行合法性校驗,包括節(jié)點 ID 有效性校驗、節(jié)點重復
登錄校驗和 IP 地址合法性校驗,校驗通過后,返回登錄成功的應用握手應答消息;
(3)鏈路建立成功之后,客戶端發(fā)送業(yè)務消息;
(4)鏈路成功之后,服務端發(fā)送心跳消息;
(5)鏈路建立成功之后,客戶端發(fā)送心跳消息;
(6)鏈路建立成功之后,服務端發(fā)送業(yè)務消息;
(7)服務端退出時,服務端關閉連接,客戶端感知對方關閉連接后,被動關閉客戶端
連接。
????????備注:需要指出的是,協(xié)議通信雙方鏈路建立成功之后,雙方可以進行全雙工通信,無
論客戶端還是服務端,都可以主動發(fā)送請求消息給對方,通信方式可以是 TWO WAY 或者
ONE WAY 。雙方之間的心跳采用 Ping-Pong 機制,當鏈路處于空閑狀態(tài)時,客戶端主動發(fā)送
Ping 消息給服務端,服務端接收到 Ping 消息后發(fā)送應答消息 Pong 給客戶端,如果客戶端連
續(xù)發(fā)送 N Ping 消息都沒有接收到服務端返回的 Pong 消息,說明鏈路已經掛死或者對方處
于異常狀態(tài),客戶端主動關閉連接,間隔周期 T 后發(fā)起重連操作,直到重連成功。

消息定義

消息定義包含兩部分:
????????消息頭;消息體。
????????在消息的定義上,因為是同步處理模式,不考慮應答消息需要填入請求消息 ID ,所以
消息頭中只有一個消息的 ID 。如果要支持異步模式,則請求消息頭和應答消息頭最好分開
設計,應答消息頭中除了包括本消息的 ID 外,還應該包括請求消息 ID ,以方便請求消息的
發(fā)送方根據請求消息 ID 做對應的業(yè)務處理。
消息體則支持 Java 對象類型的消息內容。
Netty 消息定義表
消息頭定義( Header

?

鏈路的建立

????????客戶端的說明如下:如果 A 節(jié)點需要調用 B 節(jié)點的服務,但是 A B 之間還沒有建立
物理鏈路,則有調用方主動發(fā)起連接,此時,調用方為客戶端,被調用方為服務端。
考慮到安全,鏈路建立需要通過基于 Ip 地址或者號段的黑白名單安全認證機制,作為
樣例,本協(xié)議使用基于 IP 地址的安全認證,如果有多個 Ip ,通過逗號進行分割。在實際的
商用項目中,安全認證機制會更加嚴格,例如通過密鑰對用戶名和密碼進行安全認證。
客戶端與服務端鏈路建立成功之后,由客戶端發(fā)送業(yè)務握手請求的認證消息,服務端接
收到客戶端的握手請求消息之后,如果 IP 校驗通過,返回握手成功應答消息給客戶端,應
用層鏈路建立成功。握手應答消息中消息體為 byte 類型的結果, 0 :認證成功;
-1 認證失敗;
????????服務端關閉連接。
????????鏈路建立成功之后,客戶端和服務端就可以互相發(fā)送業(yè)務消息了,在客戶端和服務端的
消息通信過程中,業(yè)務消息體的內容需要通過 MD5 進行摘要防篡改。

可靠性設計

心跳機制

????????在凌晨等業(yè)務低谷時段,如果發(fā)生網絡閃斷、連接被 Hang 住等問題時,由于沒有業(yè)務
消息,應用程序很難發(fā)現。到了白天業(yè)務高峰期時,會發(fā)生大量的網絡通信失敗,嚴重的會
導致一段時間進程內無法處理業(yè)務消息。為了解決這個問題,在網絡空閑時采用心跳機制來
檢測鏈路的互通性,一旦發(fā)現網絡故障,立即關閉鏈路,主動重連。
當讀或者寫心跳消息發(fā)生 I/O 異常的時候,說明已經中斷,此時需要立即關閉連接,如
果是客戶端,需要重新發(fā)起連接。如果是服務端,需要清空緩存的半包信息,等到客戶端重
連。 空閑的連接和超時
????????檢測空閑連接以及超時對于及時釋放資源來說是至關重要的。由于這是一項常見的任務,
Netty 特地為它提供了幾個 ChannelHandler 實現。
IdleStateHandler 當連接空閑時間太長時,將會觸發(fā)一個 IdleStateEvent 事件。然后,可
以通過在 ChannelInboundHandler 中重寫 userEventTriggered() 方法來處理該 IdleStateEvent
事件。
????????ReadTimeoutHandler 如果在指定的時間間隔內沒有收到任何的入站數據,則拋出一個
ReadTimeoutException 并關閉對應的 Channel 。可以通過重寫你的 ChannelHandler 中的
exceptionCaught() 方法來檢測該 Read-TimeoutException 。

重連機制

????????如果鏈路中斷,等到 INTEVAL 時間后,由客戶端發(fā)起重連操作,如果重連失敗,間隔周
INTERVAL 后再次發(fā)起重連,直到重連成功。
????????為了保持服務端能夠有充足的時間釋放句柄資源,在首次斷連時客戶端需要等待
INTERVAL 時間之后再發(fā)起重連,而不是失敗后立即重連。
????????為了保證句柄資源能夠及時釋放,無論什么場景下重連失敗,客戶端必須保證自身的資
源被及時釋放,包括但不現居 SocketChannel Socket 等。
????????重連失敗后,可以打印異常堆棧信息,方便后續(xù)的問題定位。

重復登錄保護

????????當客戶端握手成功之后,在鏈路處于正常狀態(tài)下,不允許客戶端重復登錄,以防止客戶
端在異常狀態(tài)下反復重連導致句柄資源被耗盡。
????????服務端接收到客戶端的握手請求消息之后,對 IP 地址進行合法性校驗,如果校驗成功,
在緩存的地址表中查看客戶端是否已經登錄,如果登錄,則拒絕重復登錄,同時關閉 TCP
鏈路,并在服務端的日志中打印握手失敗的原因。
????????客戶端接收到握手失敗的應答消息之后,關閉客戶端的 TCP 連接,等待 INTERVAL 時間
之后,再次發(fā)起 TCP 連接,直到認證成功。

實現

參考 netty-adv 模塊下的代碼
完成后 Handler 示意圖如下:
其中認證申請和認證檢查可以在完成后移除。

前期準備

????????cn.tuling.nettyadv.vo 中定義了消息有關的實體類,為了防篡改,消息體需要進行摘要,
vo 包下提供了 EncryptUtils 類,可以對消息體進行摘要,目前支持 MD5 、 SHA-1 SHA-256
三種,缺省為 MD5 ,其中 MD5 額外提供了加鹽摘要。
????????同時在 cn.tuling.nettyadv.kryocodec 中定義了有關序列化和反序列化的工具類和 Handler
本項目中序列化使用了 Kryo 序列化框架。

服務端

????????服務端中 NettyServe 類是服務端的主入口,內部使用了 ServerInit 類進行 Handler 的安
裝。
????????最先安裝的當然是解決粘包和半包問題的 Handler ,很自然,這里應該用
LengthFieldBasedFrameDecoder 進行解碼,為了實現方便,我們也沒有在消息報文中附帶消
息的長度,由 Netty 幫我們在消息報文的最開始增加長度,所以編碼器選擇了
LengthFieldPrepender 。
????????接下來,自然就是序列化和反序列化,直接使用我們在 kryocodec 下已經準備好的
KryoDecoder KryoEncoder 即可。
????????服務端需要進行登錄檢查、心跳應答、業(yè)務處理,對應著三個 handler ,于是我們分別
安裝了 LoginAuthRespHandler 、 HeartBeatRespHandler 、 ServerBusiHandler 。
????????為了節(jié)約網絡和服務器資源,如果客戶端長久沒有發(fā)送業(yè)務和心跳報文,我們認為客戶
端出現了問題,需要關閉這個連接,我們引入 Netty ReadTimeoutHandler ,當一定周期內
(默認值 50s ,我們設定為 15s )沒有讀取到對方任何消息時,會觸發(fā)一個
????????ReadTimeouttException,這時我們檢測到這個異常,需要主動關閉鏈路,并清除客戶端登錄
緩存信息,等待客戶端重連。

客戶端

????????客戶端的主類是 NettyClient ,并對外提供一個方法 send ,供業(yè)務使用內部使用了
ClientInit 類進行 Handler 的安裝。
????????最先安裝的當然是解決粘包和半包問題的 Handler ,同樣這里應該用
????????LengthFieldBasedFrameDecoder 進行解碼,編碼器選擇了 LengthFieldPrepender 。 接下來,自然就是序列化和反序列化,依然使用 KryoDecoder KryoEncoder 即可。
客戶端需要主動發(fā)出認證請求和心跳請求。
????????在 TCP 三次握手,鏈路建立后,客戶端需要進行應用層的握手認證,才能使用服務,這
個功能由 LoginAuthReqHandler 負責,而這個 Handler 在認證通過后,其實就沒用了,所以
在認證通過后,可以將這個 LoginAuthReqHandler 移除(其實服務端的認證應答
LoginAuthRespHandler 同樣也可以移除)。
????????對于發(fā)出心跳請求有兩種實現方式,一是定時發(fā)出,本框架的第一個版本就是這種實現
方式,但是這種方式其實有浪費的情況,因為如果客戶端和服務器正在正常業(yè)務通信,其實
是沒有必要發(fā)送心跳的;所以第二種方式就是,當鏈路寫空閑時,為了維持通道,避免服務
器關閉鏈接,發(fā)出心跳請求。為了實現這一點,我們首先在整個 pipeline 的最前面安裝一個
CheckWriteIdleHandler 進行寫空閑檢測,空閑時間定位 8S ,取服務器讀空閑時間 15S 的一半,
然后再安裝一個 HearBeatReqHandler ,因為寫空閑會觸發(fā)一個
????????FIRST_WRITER_IDLE_STATE_EVENT 入站事件,我們在 HearBeatReqHandler
userEventTriggered 方法中捕捉這個事件,并發(fā)出心跳請求報文。
考慮到在我們的實現中并沒有雙向心跳(即是客戶端向服務器發(fā)送心跳請求,是服務器
也向客戶端發(fā)送心跳請求),客戶端這邊同樣需要檢測服務器是否存活,所以我們客戶端這
邊安裝了一個 ReadTimeoutHandler ,捕捉 ReadTimeoutException 后提示調用者,并關閉通信
鏈路,觸發(fā)重連機制。
????????7、為了測試,單獨建立一個 BusiClient ,模擬業(yè)務方的調用。因為客戶端的網絡通信代
碼是在一個線程中單獨啟動的,為了協(xié)調主線程和通信線程的工作,我們引入了線程中的等
待通知機制。

測試

????????1、 正常情況
????????2、 客戶端宕機,服務器應能清除客戶端的緩存信息,允許客戶端重新登錄
????????3、 服務器宕機,客戶端應能發(fā)起重連
????????4、在 LoginAuthRespHandler 中進行注釋,可以模擬當服務器不處理客戶端的請求時,客戶
端在超時后重新進行登錄。

功能的增強

????????作為一個通信框架,支持診斷也是很重要的,所以我們在服務端單獨引入了一個
MetricsHandler ,可以提供:目前在線 Channel 數、發(fā)送隊列積壓消息數、讀取速率、寫出
速率相關數據,以方便應用方對自己的應用的性能和繁忙程度進行檢查和調整。
當然對于一個通信框架還可以提供 SSL 安全訪問、流控、 I/O 線程和業(yè)務線程分離、參
數的可配置化等等功能,我們就不一一展現了,同學們可以自行研究后實現,因為 Netty
上述功能已經提供了很好的支持,大家后面要學習的 Dubbo 框架源碼分析中基本都有對應
的實現。

面試難題分析

Netty 是如何解決 JDK 中的 Selector BUG 的?

????????Selector BUG: JDK NIO BUG ,例如臭名昭著的 epoll bug ,它會導致 Selector 空輪詢,
最終導致 CPU 100% 。官方聲稱在 JDK1.6 版本的 update18 修復了該問題,但是直到 JDK1.7
版本該問題仍舊存在,只不過該 BUG 發(fā)生概率降低了一些而已,它并沒有被根本解決,甚
JDK1.8 131 版本中依然存在。
JDK 官方認為這是 Linux Kernel 版本的 bug ,可以參見:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6403933
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=2147719
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6670302
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6481709
????????簡單來說,JDK 認為 linux epoll 告訴我事件來了,但是 JDK 沒有拿到任何事件 (READ 、
WRITE CONNECT 、 ACCPET) ,但此時 select() 方法不再選擇阻塞了,而是選擇返回了 0 ,于
是就會進入一種無限循環(huán),導致 CPU 100%
????????這個問題的具體原因是:在部分 Linux 2.6 kernel 中, poll epoll 對于突然中斷的
連接 socket 會對返回的 eventSet 事件集合置為 POLLHUP POLLERR eventSet 事件集合發(fā)
生了變化,這就可能導致 Selector 會被喚醒。但是這個時候 selector select 方法返回 numKeys
0 ,所以下面本應該對 key 值進行遍歷的事件處理根本執(zhí)行不了,又回到最上面的
while(true) 循環(huán),循環(huán)往復,不斷的輪詢,直到 linux 系統(tǒng)出現 100% CPU 情況,最終導致
程序崩潰。
????????Netty 解決辦法:對 Selector select 操作周期進行統(tǒng)計,每完成一次空的 select 操作
進行一次計數,若在某個周期內連續(xù)發(fā)生 N 次空輪詢,則觸發(fā)了 epoll 死循環(huán) bug 。重建
Selector ,判斷是否是其他線程發(fā)起的重建請求,若不是則將原 SocketChannel 從舊的 Selector
上去除注冊,重新注冊到新的 Selector 上,并將原來的 Selector 關閉。
具體代碼在 NioEventLoop select 方法中:

如何讓單機下 Netty 支持百萬長連接?

????????單機下能不能讓我們的網絡應用支持百萬連接?可以,但是有很多的工作要做。 操作系統(tǒng)
首先就是要突破操作系統(tǒng)的限制。
????????在 Linux 平臺上,無論編寫客戶端程序還是服務端程序,在進行高并發(fā) TCP 連接處理時,
最高的并發(fā)數量都要受到系統(tǒng)對用戶單一進程同時可打開文件數量的限制(這是因為系統(tǒng)為
每個 TCP 連接都要創(chuàng)建一個 socket 句柄,每個 socket 句柄同時也是一個文件句柄)。
????????可使用 ulimit 命令查看系統(tǒng)允許當前用戶進程打開的句柄數限制:
????????$ ulimit -n
????????1024
????????這表示當前用戶的每個進程最多允許同時打開 1024 個句柄,這 1024 個句柄中還得除
去每個進程必然打開的標準輸入,標準輸出,標準錯誤,服務器監(jiān)聽 socket, 進程間通訊的
unix socket 等文件,那么剩下的可用于客戶端 socket 連接的文件數就只有大概
1024-10=1014 個左右。也就是說缺省情況下,基于 Linux 的通訊程序最多允許同時 1014
TCP 并發(fā)連接。
????????對于想支持更高數量的 TCP 并發(fā)連接的通訊處理程序,就必須修改 Linux 對當前用戶
的進程同時打開的文件數量。
????????修改單個進程打開最大文件數限制的最簡單的辦法就是使用 ulimit 命令:
????????$ ulimit –n 1000000
????????如果系統(tǒng)回顯類似于"Operation not permitted" 之類的話,說明上述限制修改失敗,實際
上是因為在中指定的數值超過了 Linux 系統(tǒng)對該用戶打開文件數的軟限制或硬限制。因此,
就需要修改 Linux 系統(tǒng)對用戶的關于打開文件數的軟限制和硬限制。
????????軟限制(soft limit : 是指 Linux 在當前系統(tǒng)能夠承受的范圍內進一步限制一個進程同時
打開的文件數;
????????硬限制(hardlimit : 是根據系統(tǒng)硬件資源狀況(主要是系統(tǒng)內存)計算出來的系統(tǒng)最多
可同時打開的文件數量。
????????第一步,修改/etc/security/limits.conf 文件,在文件中添加如下行:
????????* soft nofile 1000000
????????* hard nofile 1000000
????????'*'號表示修改所有用戶的限制;
????????soft 和 hard 為兩種限制方式,其中 soft 表示警告的限制, hard 表示真正限制, nofile
表示打開的最大文件數。 1000000 則指定了想要修改的新的限制值,即最大打開文件數(請
注意軟限制值要小于或等于硬限制)。修改完后保存文件。
????????第二步,修改/etc/pam.d/login 文件,在文件中添加如下行:
session required /lib/security/pam_limits.so
這是告訴 Linux 在用戶完成系統(tǒng)登錄后,應該調用 pam_limits.so 模塊來設置系統(tǒng)對該用
戶可使用的各種資源數量的最大限制(包括用戶可打開的最大文件數限制),而 pam_limits.so
模塊就會從 /etc/security/limits.conf 文件中讀取配置來設置這些限制值。修改完后保存此文
件。
????????第三步,查看 Linux 系統(tǒng)級的最大打開文件數限制,使用如下命令:
???????? [speng@as4 ~]$ cat ??/proc/sys/fs/file-max
????????12158
????????這表明這臺 Linux 系統(tǒng)最多允許同時打開(即包含所有用戶打開文件數總和) 12158
文件,是 Linux 系統(tǒng)級硬限制,所有用戶級的打開文件數限制都不應超過這個數值。如果沒
有特殊需要,不應該修改此限制,除非想為用戶級打開文件數限制設置超過此限制的值。
如何修改這個系統(tǒng)最大文件描述符的限制呢?修改 sysctl.conf 文件
????????vi /etc/sysctl.conf
????????# 在末尾添加
????????fs.file_max = 1000000
????????# 立即生效
????????sysctl -p

Netty 調優(yōu)

設置合理的線程數

????????對于線程池的調優(yōu), 主要集中在用于接收海量設備 TCP 連接、 TLS 握手的 Acceptor 線程
( Netty 通常叫 boss NioEventLoop Group) , 以及用于處理網絡數據讀寫、心跳發(fā)送的 1O
工作線程池 (Nety 通常叫 work Nio EventLoop Group) 上。
????????對于 Nety 服務端 , 通常只需要啟動一個監(jiān)聽端口用于端側設備接入即可 , 但是如果服務
端集群實例比較少 , 甚至是單機 ( 或者雙機冷備 ) 部署 , 在端側設備在短時間內大量接入時 , 需要
對服務端的監(jiān)聽方式和線程模型做優(yōu)化 , 以滿足短時間內 ( 例如 30s) 百萬級的端側設備接入的
需要。
????????服務端可以監(jiān)聽多個端口, 利用主從 Reactor 線程模型做接入優(yōu)化 , 前端通過 SLB 4
7 層負載均衡。
????????主從 Reactor 線程模型特點如下 : 服務端用于接收客戶端連接的不再是一個單獨的 NO
線程 , 而是一個獨立的 NIO 線程池 ; Acceptor 接收到客戶端 TCP 連接請求并處理后 ( 可能包含接
入認證等 ), 將新創(chuàng)建的 Socketchanne 注冊到 I/O 線程池 (subReactor 線程池 ) 的某個 IO 線程 ,
由它負責 Socketchannel 的讀寫和編解碼工作 ; Acceptor 線程池僅用于客戶端的登錄、握手
和安全認證等 , 一旦鏈路建立成功 , 就將鏈路注冊到后端 sub reactor 線程池的 IO 線程 , IO
程負責后續(xù)的 IO 操作。
????????對于 IO 工作線程池的優(yōu)化 , 可以先采用系統(tǒng)默認值 ( CPU 內核數× 2) 進行性能測試 ,
性能測試過程中采集 IO 線程的 CPU 占用大小 , 看是否存在瓶頸, 具體可以觀察線程堆棧,
如果連續(xù)采集幾次進行對比 , 發(fā)現線程堆棧都停留在 Selectorlmpl. lockAndDoSelect ,則說明
IO 線程比較空閑 , 無須對工作線程數做調整。
????????如果發(fā)現 IO 線程的熱點停留在讀或者寫操作 , 或者停留在 Channelhandler 的執(zhí)行處 ,
可以通過適當調大 Nio EventLoop 線程的個數來提升網絡的讀寫性能。

心跳優(yōu)化

????????針對海量設備接入的服務端, 心跳優(yōu)化策略如下。 (1) 要能夠及時檢測失效的連接 , 并將其剔除 , 防止無效的連接句柄積壓 , 導致 OOM 等問題
????????(2)設置合理的心跳周期 , 防止心跳定時任務積壓 , 造成頻繁的老年代 GC( 新生代和老年代
都有導致 STW GC, 不過耗時差異較大 ), 導致應用暫停
????????(3)使用 Nety 提供的鏈路空閑檢測機制 , 不要自己創(chuàng)建定時任務線程池 , 加重系統(tǒng)的負擔 ,
以及增加潛在的并發(fā)安全問題。
????????當設備突然掉電、連接被防火墻擋住、長時間 GC 或者通信線程發(fā)生非預期異常時 , 會導
致鏈路不可用且不易被及時發(fā)現。特別是如果異常發(fā)生在凌晨業(yè)務低谷期間 , 當早晨業(yè)務高
峰期到來時 , 由于鏈路不可用會導致瞬間大批量業(yè)務失敗或者超時 , 這將對系統(tǒng)的可靠性產生
重大的威脅。
????????從技術層面看, 要解決鏈路的可靠性問題 , 必須周期性地對鏈路進行有效性檢測。目前最
流行和通用的做法就是心跳檢測。心跳檢測機制分為三個層面:
????????(1)TCP 層的心跳檢測 , TCP Keep-Alive 機制 , 它的作用域是整個 TCP 協(xié)議棧。
????????(2)協(xié)議層的心跳檢測 , 主要存在于長連接協(xié)議中 , 例如 MQTT
????????(3)應用層的心跳檢測 , 它主要由各業(yè)務產品通過約定方式定時給對方發(fā)送心跳消息實現。
心跳檢測的目的就是確認當前鏈路是否可用 , 對方是否活著并且能夠正常接收和發(fā)送消
息。作為高可靠的 NIO 框架 ,Nety 也提供了心跳檢測機制。
一般的心跳檢測策略如下。
????????(1)連續(xù) N 次心跳檢測都沒有收到對方的 Pong 應答消息或者 Ping 請求消息 , 則認為鏈路
已經發(fā)生邏輯失效 , 這被稱為心跳超時。
????????(2)在讀取和發(fā)送心跳消息的時候如果直接發(fā)生了 IO 異常 , 說明鏈路已經失效 , 這被稱為
心跳失敗。無論發(fā)生心跳超時還是心跳失敗 , 都需要關閉鏈路 , 由客戶端發(fā)起重連操作 , 保證鏈
路能夠恢復正常。
Nety 提供了三種鏈路空閑檢測機制 , 利用該機制可以輕松地實現心跳檢測
????????(1)讀空閑 , 鏈路持續(xù)時間 T 沒有讀取到任何消息。
????????(2)寫空閑 , 鏈路持續(xù)時間 T 沒有發(fā)送任何消息
????????(3)讀寫空閑 , 鏈路持續(xù)時間 T 沒有接收或者發(fā)送任何消息
? ? ?對于百萬級的服務器,一般不建議很長的心跳周期和超時時長。

接收和發(fā)送緩沖區(qū)調優(yōu)

????????在一些場景下, 端側設備會周期性地上報數據和發(fā)送心跳 , 單個鏈路的消息收發(fā)量并不大 ,
針對此類場景 , 可以通過調小 TCP 的接收和發(fā)送緩沖區(qū)來降低單個 TCP 連接的資源占用率
當然對于不同的應用場景 , 收發(fā)緩沖區(qū)的最優(yōu)值可能不同 , 用戶需要根據實際場景 , 結合
性能測試數據進行針對性的調優(yōu)

合理使用內存池

????????隨著 JVM 虛擬機和 JT 即時編譯技術的發(fā)展 , 對象的分配和回收是一個非常輕量級的工作。
但是對于緩沖區(qū) Buffer, 情況卻稍有不同 , 特別是堆外直接內存的分配和回收 , 是一個耗時的
操作。 為了盡量重用緩沖區(qū) ,Nety 提供了基于內存池的緩沖區(qū)重用機制。
????????在百萬級的情況下, 需要為每個接入的端側設備至少分配一個接收和發(fā)送 ByteBuf 緩沖
區(qū)對象 , 采用傳統(tǒng)的非池模式 , 每次消息讀寫都需要創(chuàng)建和釋放 ByteBuf 對象 , 如果有 100 萬個
連接 , 每秒上報一次數據或者心跳 , 就會有 100 萬次 / 秒的 ByteBuf 對象申請和釋放 , 即便服務
端的內存可以滿足要求 ,GC 的壓力也會非常大。
????????以上問題最有效的解決方法就是使用內存池, 每個 NioEventLoop 線程處理 N 個鏈路 ,
線程內部 , 鏈路的處理是串行的。假如 A 鏈路首先被處理 , 它會創(chuàng)建接收緩沖區(qū)等對象 , 待解碼
完成 , 構造的 POJO 對象被封裝成任務后投遞到后臺的線程池中執(zhí)行 , 然后接收緩沖區(qū)會被釋
, 每條消息的接收和處理都會重復接收緩沖區(qū)的創(chuàng)建和釋放。如果使用內存池 , 則當 A 鏈路
接收到新的數據報時 , NioEventLoop 的內存池中申請空閑的 ByteBuf, 解碼后調用 release
ByteBuf 釋放到內存池中 , 供后續(xù)的 B 鏈路使用。
????????Nety 內存池從實現上可以分為兩類 : 堆外直接內存和堆內存。由于 Byte Buf 主要用于網
IO 讀寫 , 因此采用堆外直接內存會減少一次從用戶堆內存到內核態(tài)的字節(jié)數組拷貝 , 所以
性能更高。由于 DirectByteBuf 的創(chuàng)建成本比較高 , 因此如果使用 DirectByteBuf, 則需要配合
內存池使用 , 否則性價比可能還不如 Heap Byte 。
????????Netty 默認的 IO 讀寫操作采用的都是內存池的堆外直接內存模式 , 如果用戶需要額外使
ByteBuf, 建議也采用內存池方式 ; 如果不涉及網絡 IO 操作 ( 只是純粹的內存操作 ), 可以使用
堆內存池 , 這樣內存的創(chuàng)建效率會更高一些。

IO 線程和業(yè)務線程分離

????????如果服務端不做復雜的業(yè)務邏輯操作, 僅是簡單的內存操作和消息轉發(fā) , 則可以通過調大
NioEventLoop 工作線程池的方式 , 直接在 IO 線程中執(zhí)行業(yè)務 Channelhandler, 這樣便減少了一
次線程上下文切換 , 性能反而更高。
????????如果有復雜的業(yè)務邏輯操作, 則建議 IO 線程和業(yè)務線程分離 , 對于 IO 線程 , 由于互相之間
不存在鎖競爭 , 可以創(chuàng)建一個大的 NioEvent Loop Group 線程組 , 所有 Channel 都共享同一個
線程池。
????????對于后端的業(yè)務線程池, 則建議創(chuàng)建多個小的業(yè)務線程池 , 線程池可以與 IO 線程綁定 ,
樣既減少了鎖競爭 , 又提升了后端的處理性能。

針對端側并發(fā)連接數的流控

????????無論服務端的性能優(yōu)化到多少, 都需要考慮流控功能。當資源成為瓶頸 , 或者遇到端側設
備的大量接入 , 需要通過流控對系統(tǒng)做保護。流控的策略有很多種,比如針對端側連接數的
流控:
????????在 Nety , 可以非常方便地實現流控功能 : 新增一個 FlowControlchannelhandler ,然后添
加到 ChannelPipeline 靠前的位置 , 覆蓋 channelActive() 方法 , 創(chuàng)建 TCP 鏈路后 , 執(zhí)行流控邏輯 ,
如果達到流控閾值 , 則拒絕該連接 , 調用 ChannelHandler Context close( 方法關閉連接。

JVM 層面相關性能優(yōu)化

????????當客戶端的并發(fā)連接數達到數十萬或者數百萬時, 系統(tǒng)一個較小的抖動就會導致很嚴重
的后果 , 例如服務端的 GC, 導致應用暫停 (STW) GC 持續(xù)幾秒 , 就會導致海量的客戶端設備掉 線或者消息積壓 , 一旦系統(tǒng)恢復 , 會有海量的設備接入或者海量的數據發(fā)送很可能瞬間就把服
務端沖垮。
????????JVM 層面的調優(yōu)主要涉及 GC 參數優(yōu)化 ,GC 參數設置不當會導致頻繁 GC, 甚至 OOM 異常 ,
對服務端的穩(wěn)定運行產生重大影響。

1.確定 GC 優(yōu)化目標

GC( 垃圾收集 ) 有三個主要指標。
????????(1)吞吐量 : 是評價 GC 能力的重要指標 , 在不考慮 GC 引起的停頓時間或內存消耗時 , 吞吐
量是 GC 能支撐應用程序達到的最高性能指標。
????????(2)延遲 :GC 能力的最重要指標之一 , 是由于 GC 引起的停頓時間 , 優(yōu)化目標是縮短延遲時
間或完全消除停頓 (STW), 避免應用程序在運行過程中發(fā)生抖動。
????????(3)內存占用 :GC 正常時占用的內存量。
JVM GC 調優(yōu)的三個基本原則如下。
????????(1) Minor go 回收原則 : 每次新生代 GC 回收盡可能多的內存 , 減少應用程序發(fā)生 Full gc
頻率。
? ? ? ? (2)GC 內存最大化原則 : 垃圾收集器能夠使用的內存越大 , 垃圾收集效率越高 , 應用程序運
行也越流暢。但是過大的內存一次 Full go 耗時可能較長 , 如果能夠有效避免 FullGC, 就需要做
精細化調優(yōu)。
????????(3)3 選 2 原則 : 吞吐量、延遲和內存占用不能兼得 , 無法同時做到吞吐量和暫停時間都最
優(yōu) , 需要根據業(yè)務場景做選擇。對于大多數應用 , 吞吐量優(yōu)先 , 其次是延遲。當然對于時延敏感
型的業(yè)務 , 需要調整次序。

2.確定服務端內存占用

????????在優(yōu)化 GC 之前 , 需要確定應用程序的內存占用大小 , 以便為應用程序設置合適的內存 ,
GC 效率。內存占用與活躍數據有關 , 活躍數據指的是應用程序穩(wěn)定運行時長時間存活的
Java 對象?;钴S數據的計算方式 : 通過 GC 日志采集 GC 數據 , 獲取應用程序穩(wěn)定時老年代占用
Java 堆大小 , 以及永久代 ( 元數據區(qū) ) 占用的 Java 堆大小 , 兩者之和就是活躍數據的內存占用
大小。

3.GC 優(yōu)化過程

????????1、 GC 數據的采集和研讀
????????2、設置合適的 JVM 堆大小
????????3、選擇合適的垃圾回收器和回收策略
當然具體如何做,請參考 JVM 相關課程。而且 GC 調優(yōu)會是一個需要多次調整的過程,
期間不僅有參數的變化,更重要的是需要調整業(yè)務代碼。

什么是水平觸發(fā)(LT)和邊緣觸發(fā)(ET)

????????Level_triggered(水平觸發(fā) ) :當被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時, epoll_wait()
會通知處理程序去讀寫。如果這次沒有把數據一次性全部讀寫完,那么下次調用 epoll_wait() 時,它還會通知你在上沒讀寫完的文件描述符上繼續(xù)讀寫,當然如果你一直不去讀寫,它會
一直通知你。
????????Edge_triggered(邊緣觸發(fā) ) :當被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時, epoll_wait()
會通知處理程序去讀寫。如果這次沒有把數據全部讀寫完,那么下次調用 epoll_wait() 時,
它不會通知你,也就是它只會通知你一次,直到該文件描述符上出現第二次可讀寫事件才會
通知你。這種模式比水平觸發(fā)效率高,系統(tǒng)不會充斥大量你不關心的就緒文件描述符!!
select() poll() 模型都是水平觸發(fā)模式,信號驅動 IO 是邊緣觸發(fā)模式, epoll() 模型即支
持水平觸發(fā),也支持邊緣觸發(fā),默認是水平觸發(fā)。 JDK 中的 select 實現是水平觸發(fā),而 Netty
提供的 Epoll 的實現中是邊緣觸發(fā)。

請說說 DNS 域名解析的全過程

本題其實是“瀏覽器中輸入 URL 到返回頁面的全過程”這個題目的衍生題:
????????1.根據域名,進行 DNS 域名解析;
????????2.拿到解析的 IP 地址,建立 TCP 連接;
????????3.向 IP 地址,發(fā)送 HTTP 請求;
????????4.服務器處理請求;
????????5.返回響應結果;
????????6.關閉 TCP 連接;
????????7.瀏覽器解析 HTML;
????????8.瀏覽器布局渲染;
????????可見 DNS 域名解析是其中的一部分。
????????DNS 一個由分層的服務系統(tǒng),大致說來,有 3 種類型的 DNS 服務器:根 DNS 服務器、頂
級域(Top-Level Domain,TLD) DNS 服務器和權威 DNS 服務器。
????????根 DNS 服務器。截止到 2022 年 4 月 22 日,有 1533 個根名字服務器遍及全世界,可到
https://root-servers.org/ 查詢分布情況,根名字服務器提供 TLD 服務器的 IP 地址。
????????頂級域(DNS)服務器。對于每個頂級域(如 com、org、net、edu 和 gov)和所有國家
的頂級域(如 uk、fr、ca 和 jp),都有 TLD 服務器(或服務器集群)。TLD 服務器提供了
權威 DNS 服務器的 IP 地址。
????????權威 DNS 服務器。在因特網上的每個組織機構必須提供公共可訪問的 DNS 記錄,這些
記錄將這些主機的名字映射為 IP 地址。一個組織機構的權威 DNS 服務器收藏了這些 DNS 記
錄。一個組織機構能夠選擇實現它自己的權威 DNS 服務器以保存這些記錄;也可以交由商
用 DNS 服務商存儲在這個服務提供商的一個權威 DNS 服務器中,比如阿里云旗下的中國萬
網。
????????有另一類重要的 DNS 服務器,稱為本地 DNS 服務器( local DNS server)。嚴格說來,
一個本地 DNS 服務器并不屬于該服務器的層次結構,但它對 DNS 層次結構是至關重要的。
每個 ISP 都有一臺本地 DNS 服務器。同時很多路由器中也會附帶 DNS 服務。
????????當主機發(fā)出 DNS 請求時,該請求被發(fā)往本地 DNS 服務器,它起著代理的作用,并將該請
求轉發(fā)到 DNS 服務器層次結構中,同時本地 DNS 服務器也會緩存 DNS 記錄。 所以一個 DNS 客戶要決定主機名 www.baidu.com 的 IP 地址。粗略說來,將發(fā)生下列事 件??蛻羰紫扰c根服務器之一聯(lián)系,它將返回頂級域名 com 的 TLD 服務器的 IP 地址。該客 戶則與這些 TLD 服務器之一聯(lián)系,它將為 baidu.com 返回權威服務器的 IP 地址。最后,該 客戶與 baidu.com 權威服務器之一聯(lián)系,它為主機名 www.baidu.com 返回其 IP 地址。
http://www.risenshineclean.com/news/34167.html

相關文章:

  • 品牌廣告設計制作公司網站源碼班級優(yōu)化大師的功能有哪些
  • wordpress使用兩個主題如何推廣seo
  • 獨立站都有哪些百度快速排名提升
  • 網站投票活動怎么做百度域名注冊查詢
  • 沒有網站怎么做seob站推廣平臺
  • 網站報名怎么做市場營銷培訓
  • 網站目錄鏈接怎么做天津百度推廣電話
  • 粉色做網站背景圖片競價推廣是什么意思
  • 臨汾哪做網站seo關鍵詞優(yōu)化推廣哪家好
  • 京東淘寶網站是怎么做的360免費做網站
  • 微信鏈接網頁網站制作網站seo優(yōu)化推廣
  • wordpress quizzin網站怎樣優(yōu)化關鍵詞好
  • 大興智能網站建設哪家好企業(yè)營銷策劃
  • 吉林省住房城鄉(xiāng)建設廳網站首頁什么是搜索推廣
  • 設計網站價格鄭州seo軟件
  • 湖南網絡公司網站建設seo教學平臺
  • 網站如何運營賺錢線下推廣方式都有哪些
  • 慈溪做網站網站打開速度優(yōu)化
  • 公安網站建設公司網站與推廣
  • 莆田做網站的公司住房和城鄉(xiāng)建設部官網
  • 個體做外貿的網站2021百度模擬點擊工具
  • 企業(yè)微信網站建設東莞做網站哪里好
  • 南通公司網站建設怎么做網站推廣和宣傳
  • 空調維修技術支持東莞網站建設國家最新新聞
  • wordpress簡約企業(yè)主題下載廣州seo技術外包公司
  • 網絡推廣合同網站seo優(yōu)化服務商
  • 北京設計院排名前十強湖南網站seo地址
  • 佛山百度網站排名深圳建站公司
  • 惠州網站建設找惠州邦百度云盤網頁登錄入口
  • 查看網站外鏈代碼百度高級搜索指令