netty建立聊天室服務端及單機併發測試結果
前言
netty應該是Java網路通訊開發的殺手級框架,它提供非同步,事件驅動的網路應用程式框架和工具。
至於netty的概念和優點很多,在此我就不獻醜了,我純粹實在官方文件的小例子基礎上做一些測試以印證自己心中的想法。
首先搭建一個netty服務端,新建一個maven專案,引入依賴:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.30.Final</version>
</dependency>
handler處理器
package cn.com.handler.server;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
/**
* @Auther: kc
* @Date: 2018/10/8 20:28
* @Description:
*/
public class SimpleChatServerHandler extends SimpleChannelInboundHandler<String> { // (1)
public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
//服務端從客戶端收到新的連線的時候,客戶端的channel存入channerGroup列表中,並通知列表中的其他客戶端
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // (2)
Channel incoming = ctx.channel();
// Broadcast a message to multiple Channels
channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
channels.add(ctx.channel());
}
//當從服務端收到客戶端斷開時,客戶端自動從channelgroup中離開,並通知其它客戶端
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
Channel incoming = ctx.channel();
// Broadcast a message to multiple Channels
channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 離開\n");
// A closed Channel is automatically removed from ChannelGroup,
// so there is no need to do "channels.remove(ctx.channel());"
}
//每當服務端讀到客戶端寫入資訊時,將資訊轉發給其它客戶端的channel
@Override
protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { // (4)
Channel incoming = ctx.channel();
for (Channel channel : channels) {
if (channel != incoming){
channel.writeAndFlush("[" + incoming.remoteAddress() + "]" + s + "\n");
} else {
channel.writeAndFlush("[you]" + s + "\n");
}
}
}
//服務端監聽到客戶端活動
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"線上");
}
//服務端監聽到客戶端不活動
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"掉線");
}
//當處理方法出現throwable物件才會被呼叫,即當netty由於IO錯誤或者處理器在處理事件時丟擲的異常
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)
Channel incoming = ctx.channel();
System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"異常");
// 當出現異常就關閉連線
cause.printStackTrace();
ctx.close();
}
}
SimpleChatServerInitializer.java
用來增加多個的處理類到 ChannelPipeline 上,包括編碼、解碼、SimpleChatServerHandler 等。
package cn.com.handler.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* @Auther: kc
* @Date: 2018/10/8 20:35
* @Description: 用來增加多個的處理類到ChannelPipeline,包括編碼、解碼、simpleChatServerHandler
*/
public class SimpleChatServerInitializer extends
ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatServerHandler());
System.out.println("SimpleChatClient:"+ch.remoteAddress() +"連線上");
}
}
SimpleChatServer.java
編寫一個 main() 方法來啟動服務端:
package cn.com.handler.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @Auther: kc
* @Date: 2018/10/8 20:38
* @Description:
*/
public class SimpleChatServer {
private int port;
public SimpleChatServer(int port) {
this.port = port;
}
public void run() throws Exception {
//用來處理IO操作的多執行緒事件迴圈器,boss用來接收接進來的連線,worker用來處理已經接收的連線,一旦boss收到連線就會把連線資訊註冊到worker上
EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); // ServerBootStrap是一個啟動NIO服務的輔助啟動類
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // 指定使用NioServerSocketChannel類來舉例說明一個新的channel如何接收進來的連線
.childHandler(new SimpleChatServerInitializer()) //呼叫SimpleChatServerInitializer
.option(ChannelOption.SO_BACKLOG, 128) // (5)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
System.out.println("SimpleChatServer 啟動了");
// 繫結埠,開始接收進來的連線
ChannelFuture f = b.bind(port).sync(); // (7)
// 等待伺服器 socket 關閉 。
// 在這個例子中,這不會發生,但你可以優雅地關閉你的伺服器。
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
System.out.println("SimpleChatServer 關閉了");
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new SimpleChatServer(port).run();
}
}
啟動main方法
Jmeter測試
我是按照官網的例子寫的,在自己電腦(4核,8G記憶體/沒測試之前記憶體用了4。5G,cpu佔用15%左右)跑服務端,跑jmeter測試,沒經過任何優化,首先我用1秒鐘500次請求
可以發現請求的一瞬間cpu佔用會到80%,而記憶體卻沒有多大佔用。
然後我用100秒的時間去請求10000次,這裡截不了圖,因為會很卡,大概到6000個請求的時候,就會吃完我電腦剩下的記憶體,但是cpu應該還猶有餘力。
總結
我並不知道我這樣的測試是否合理,但是看來一臺8G,4核的伺服器host1w個請求肯定是可以得,我覺得應該還可以優化讓netty接受更多的請求,繼續學習吧!
相關文章
- Python_服務端效能高併發測試Python服務端
- Netty服務端開發及效能最佳化Netty服務端
- grequests 執行併發測試與 jmeter 併發結果對比JMeter
- YApi 服務端測試新增 globalCookie ,相容自動化觸發服務端測試功能API服務端Cookie
- 服務端測試開發必備技能:Mock測試服務端Mock
- Spring Boot單元測試之服務層測試總結Spring Boot
- Netty版本 簡單聊天室Netty
- 單元/整合測試服務
- day114:MoFang:基於支付寶沙箱測試環境完成建立充值訂單介面&服務端處理支付結果的同步通知和非同步通知服務端非同步
- Netty入門系列(1) --使用Netty搭建服務端和客戶端Netty服務端客戶端
- 測試結果
- 服務端測試是什麼?怎麼測?服務端
- 整車電效能裝置開發及測試服務
- 基於Java NIO 寫的一個簡單版 Netty 服務端JavaNetty服務端
- Netty 框架學習 —— 單元測試Netty框架
- Qt實現網路聊天室(客戶端,服務端)QT客戶端服務端
- 效能測試-服務端瓶頸分析思路服務端
- Netty(4)初步瞭解 Netty服務端初始化過程Netty服務端
- Netty原始碼分析(二):服務端啟動Netty原始碼服務端
- Netty系列文章之服務端啟動分析Netty服務端
- C#建立WebSocket服務端C#Web服務端
- Netty高階應用及聊天室實戰Netty
- 遊戲服務端的高併發和高可用遊戲服務端
- 從服務端視角看高併發難題服務端
- 挑戰 - 微服務架構下的服務端測試微服務架構服務端
- 主流 go-web 服務端框架效能測試GoWeb服務端框架
- 服務端效能測試你應該知道的服務端
- [20190213]測試服務端開啟那些埠.txt服務端
- 如何使用jMeter對某個OData服務進行高併發效能測試JMeter
- Netty原始碼解析 -- 服務端啟動過程Netty原始碼服務端
- python建立tcp服務端和客戶端PythonTCP服務端客戶端
- 單元測試&反射機制(未完結)反射
- iOS內購 - 服務端票據驗證及漏單引發的思考iOS服務端
- HMI測試服務
- 服務端常見服務安裝及配置服務端
- 服務端測試很牛逼?不要慫,幹它服務端
- go語言遊戲服務端開發(三)——服務機制Go遊戲服務端
- Gateway整合Netty服務GatewayNetty