三分鐘構建高效能WebSocket服務 | 超優雅的Springboot整合Netty方案
前言
每當使用SpringBoot進行Weboscket開發時,最容易想到的就是
spring-boot-starter-websocket
(或spring-websocket
)。它可以讓我們使用註解,很簡單的進行Websocket開發,讓我們更多的關注業務邏輯。它底層使用的是Tomcat,且不說把整個Tomcat放進一個WebSocket服務中是否會太重,但在大資料量高併發的場景下,它的表現並不是非常理想。
Netty一款高效能的NIO網路程式設計框架,在推送量激增時,表現依然出色。(關於效能與表現的討論,網上很多,這裡不過多說明。)很多流行開源專案都在使用Netty,如:Dubbo、Storm、Spark、Elasticsearch、Apache Cassandra等,這得益於Netty的併發高、傳輸快、封裝好等特點。
但是,要在SpringBoot專案中整合Netty來開發WebSocket不是一件舒服的事,這會讓你過多的關注非業務邏輯的實現。那麼,是否有一款框架,能使得在SpringBoot專案中使用Netty開發WebSocket變得簡單,甚至優雅,並且可以從使用
spring-boot-starter-websocket
開發的專案無縫的遷移過來呢?
netty-websocket-spring-boot-starter
這是個開源的框架。通過它,我們可以像spring-boot-starter-websocket
一樣使用註解進行開發,只需關注需要的事件(如OnMessage)。並且底層是使用Netty,當需要調參的時候只需要修改配置引數即可,無需過多的關心handler的設定。
快速入門
- 建立SpringBoot專案(v2.0.0以上)並新增依賴:
<dependency>
<groupId>org.yeauty</groupId>
<artifactId>netty-websocket-spring-boot-starter</artifactId>
<version>0.6.2</version>
</dependency>
- new一個
ServerEndpointExporter
物件,交給Spring容器,表示要開啟WebSocket功能:
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
- 在端點類上加上
@ServerEndpoint
、@Component
註解,並在相應的方法上加上@OnOpen
、@OnClose
、@OnError
、@OnMessage
註解(不想關注某個事件可不新增對應的註解):
@ServerEndpoint
@Component
public class MyWebSocket {
@OnOpen
public void onOpen(Session session, HttpHeaders headers) throws IOException {
System.out.println("new connection");
}
@OnClose
public void onClose(Session session) throws IOException {
System.out.println("one connection closed");
}
@OnError
public void onError(Session session, Throwable throwable) {
throwable.printStackTrace();
}
@OnMessage
public void OnMessage(Session session, String message) {
System.out.println(message);
session.sendText("Hello Netty!");
}
}
- 一個高效能的WebSocket服務端就完成了,直接run起來就可以了。
測試
- 服務端是寫完了,接下來需要測試一下,看看效果
- 首先,新建一個html檔案,把頁面擼出來
<!DOCTYPE html>
<html lang="en">
<body>
<div id="msg"></div>
<input type="text" id="text">
<input type="submit" value="send" onclick="send()">
</body>
<script>
var msg = document.getElementById("msg");
var wsServer = 'ws://127.0.0.1:80';
var websocket = new WebSocket(wsServer);
//監聽連線開啟
websocket.onopen = function (evt) {
msg.innerHTML = "The connection is open";
};
//監聽伺服器資料推送
websocket.onmessage = function (evt) {
msg.innerHTML += "<br>" + evt.data;
};
//監聽連線關閉
websocket.onclose = function (evt) {
alert("連線關閉");
};
function send() {
var text = document.getElementById("text").value
websocket.send(text);
}
</script>
</html>
- 頁面擼完,直接用Chrome開啟上面html檔案即可連上你的WebSocket服務。
總結
這個框架是基於Netty的,所以直接使用Netty優化時的理念即可。如:堆外記憶體的0拷貝、接收及傳送緩衝區的調整、高低寫水位的調整等。
生產環境的專案在充分調優後,Netty甚至能比Tomcat高效20倍。(當然,這是特定的場景下)