搭建生产级的Netty项目
Netty是Trustin Lee在2004年开发的一款高性能的网络应用程序框架。相比于JDK自带的NIO,Netty做了相当多的增强,且隔离了jdk nio的实现细节,API也比较友好,还支持流量整形等高级特性。在我们常见的一些开源项目中已经普遍的应用到了Netty,比如Dubbo、Elasticsearch、Zookeeper等。
Netty的具体开发
提示:因代码相对较多,这里只展示其主要部分,至于项目中用到的编解码器、工具类,请直接拉到最后下载源码!也欢迎顺手给个Star~
需要的依赖
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-jmx</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.29.Final</version>
</dependency>
Client端代码
package com.example.nettydemo.client;
import com.example.nettydemo.client.codec.*;
import com.example.nettydemo.client.codec.dispatcher.OperationResultFuture;
import com.example.nettydemo.client.codec.dispatcher.RequestPendingCenter;
import com.example.nettydemo.client.codec.dispatcher.ResponseDispatcherHandler;
import com.example.nettydemo.common.RequestMessage;
import com.example.nettydemo.common.string.StringOperation;
import com.example.nettydemo.util.IdUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import javax.net.ssl.SSLException;
import java.util.concurrent.ExecutionException;
public class Client {
public static void main(String[] args) throws InterruptedException, ExecutionException, SSLException {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
//客户端连接服务器最大允许时间,默认为30s
bootstrap.option(NioChannelOption.CONNECT_TIMEOUT_MILLIS, 30 * 1000); //10s
NioEventLoopGroup group = new NioEventLoopGroup();
try {
bootstrap.group(group);
RequestPendingCenter requestPendingCenter = new RequestPendingCenter();
LoggingHandler loggingHandler = new LoggingHandler(LogLevel.INFO);
bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new FrameDecoder());
pipeline.addLast(new FrameEncoder());
pipeline.addLast(new ProtocolEncoder());
pipeline.addLast(new ProtocolDecoder());
pipeline.addLast(new ResponseDispatcherHandler(requestPendingCenter));
pipeline.addLast(new OperationToRequestMessageEncoder());
// pipeline.addLast(loggingHandler);
}
});
//连接服务
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8888);
//因为future是异步执行,所以需要先连接上后,再进行下一步操作
channelFuture.sync();
long streamId = IdUtil.nextId();
/**
* 发送数据测试,按照定义的规则组装数据
*/
// OrderOperation orderOperation = new OrderOperation(1001, "你好啊,hi");
RequestMessage requestMessage = new RequestMessage(streamId, new StringOperation(1234, "你好啊,hi"));
//将future放入center
OperationResultFuture operationResultFuture = new OperationResultFuture();
requestPendingCenter.add(streamId, operationResultFuture);
//发送消息
for (int i = 0; i < 10; i++) {
channelFuture.channel().writeAndFlush(requestMessage);
}
//阻塞等待结果,结果来了之后会调用ResponseDispatcherHandler去set结果
// OperationResult operationResult = operationResultFuture.get();
// //将结果打印
// System.out.println("返回:"+operationResult);
channelFuture.channel().closeFuture().get();
} finally {
group.shutdownGracefully();
}
}
}
Server端代码
package com.example.nettydemo.server;
import com.example.nettydemo.server.codec.FrameDecoder;
import com.example.nettydemo.server.codec.FrameEncoder;
import com.example.nettydemo.server.codec.ProtocolDecoder;
import com.example.nettydemo.server.codec.ProtocolEncoder;
import com.example.nettydemo.server.handler.MetricsHandler;
import com.example.nettydemo.server.handler.ServerIdleCheckHandler;
import com.example.nettydemo.server.handler.ServerProcessHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.flush.FlushConsolidationHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;
import lombok.extern.slf4j.Slf4j;
import javax.net.ssl.SSLException;
import java.security.cert.CertificateException;
import java.util.concurrent.ExecutionException;
/**
* netty server 入口
*/
@Slf4j
public class Server {
public static void main(String... args) throws InterruptedException, ExecutionException, CertificateException, SSLException {
ServerBootstrap serverBootstrap = new ServerBootstrap();
//设置channel模式,因为是server所以使用NioServerSocketChannel
serverBootstrap.channel(NioServerSocketChannel.class);
//最大的等待连接数量
serverBootstrap.option(NioChannelOption.SO_BACKLOG, 1024);
//设置是否启用 Nagle 算法:用将小的碎片数据连接成更大的报文 来提高发送效率。
//如果需要发送一些较小的报文,则需要禁用该算法
serverBootstrap.childOption(NioChannelOption.TCP_NODELAY, true);
//设置netty自带的log,并设置级别
serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
//thread
//用户指定线程名
NioEventLoopGroup bossGroup = new NioEventLoopGroup(0, new DefaultThreadFactory("boss"));
NioEventLoopGroup workGroup = new NioEventLoopGroup(0, new DefaultThreadFactory("worker"));
UnorderedThreadPoolEventExecutor businessGroup = new UnorderedThreadPoolEventExecutor(10, new DefaultThreadFactory("business"));
//只能使用一个线程,因GlobalTrafficShapingHandler比较轻量级
NioEventLoopGroup eventLoopGroupForTrafficShaping = new NioEventLoopGroup(0, new DefaultThreadFactory("TS"));
try {
//设置react方式
serverBootstrap.group(bossGroup, workGroup);
//metrics
MetricsHandler metricsHandler = new MetricsHandler();
//trafficShaping流量整形
//long writeLimit 写入时控制, long readLimit 读取时控制 具体设置看业务修改
GlobalTrafficShapingHandler globalTrafficShapingHandler = new GlobalTrafficShapingHandler(eventLoopGroupForTrafficShaping, 10 * 1024 * 1024, 10 * 1024 * 1024);
//log
LoggingHandler debugLogHandler = new LoggingHandler(LogLevel.DEBUG);
LoggingHandler infoLogHandler = new LoggingHandler(LogLevel.INFO);
//设置childHandler,按执行顺序放
serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("debugLog", debugLogHandler);
pipeline.addLast("tsHandler", globalTrafficShapingHandler);
pipeline.addLast("metricHandler", metricsHandler);
pipeline.addLast("idleHandler", new ServerIdleCheckHandler());
pipeline.addLast("frameDecoder", new FrameDecoder());
pipeline.addLast("frameEncoder", new FrameEncoder());
pipeline.addLast("protocolDecoder", new ProtocolDecoder());
pipeline.addLast("protocolEncoder", new ProtocolEncoder());
pipeline.addLast("infoLog", infoLogHandler);
//对flush增强,减少flush次数牺牲延迟增强吞吐量
pipeline.addLast("flushEnhance", new FlushConsolidationHandler(10, true));
//为业务处理指定单独的线程池
pipeline.addLast(businessGroup, new ServerProcessHandler());//businessGroup,
}
});
//绑定端口并阻塞启动
ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
businessGroup.shutdownGracefully();
eventLoopGroupForTrafficShaping.shutdownGracefully();
}
}
}
最后
以上介绍了Netty的基本用法,在代码中也做了一部分的关键注释,但可能还会有许多不足,也不可能满足所有人的要求,大家可根据自己的实际需求去改造此项目。附上源码地址netty源码
持续学习,记录点滴。更多文章请访问 文章首发
搭建生产级的Netty项目的更多相关文章
- Java全栈程序员之07:IDEA中使用MAVEN构架生产级的Web项目
在上一篇我们介绍了如何在IDEA中使用MAVEN,以及如何创建依赖等.那么在这一篇中,我们就试图搭建一个生产级的解决方案,大家可以使用这个解决方案作为骨架代码来搭建自己的开发环境. 在这里,我们要完成 ...
- 【分布式事务】基于RocketMQ搭建生产级消息集群?
导读 目前很多互联网公司的系统都在朝着微服务化.分布式化系统的方向在演进,这带来了很多好处,也带来了一些棘手的问题,其中最棘手的莫过于数据一致性问题了.早期我们的软件功能都在一个进程中,数据的一致性可 ...
- 前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例
使用vue-cli可以规范项目,提高开发效率,但是使用vue-cli时需要一些ECMAScript6的知识,特别是ES6中的模块管理内容,本章先介绍ES6中的基础与模块化的内容再使用vue-cli开发 ...
- Maven 搭建spring boot多模块项目(附源码),亲测可以,感谢原创
原创地址:https://segmentfault.com/a/1190000005020589 我的DEMO码云地址,持续添加新功能: https://gitee.com/itbase/Spring ...
- 使用maven搭建ssm框架的javaweb项目
目前主流的javaweb项目,常会用到ssm(Spring+Spring MVC+Mybatis)框架来搭建项目的主体框架,本篇介绍搭建SSM框架的maven项目的实施流程.记之共享! 一.SSM框架 ...
- Maven 搭建spring boot多模块项目
Maven 搭建spring boot多模块项目 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom ...
- 使用 Sealos 在 3 分钟内快速部署一个生产级别的 Kubernetes 高可用集群
本文首发于:微信公众号「运维之美」,公众号 ID:Hi-Linux. 「运维之美」是一个有情怀.有态度,专注于 Linux 运维相关技术文章分享的公众号.公众号致力于为广大运维工作者分享各类技术文章和 ...
- 微信自研生产级paxos类库PhxPaxos实现原理介绍
转载自: http://mp.weixin.qq.com/s?__biz=MzI4NDMyNTU2Mw==&mid=2247483695&idx=1&sn=91ea4229 ...
- react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)
react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redu ...
随机推荐
- 从赴美IPO绝迹 看那些烧成泡沫的互联网企业
曾经,赴美上市是很多中国企业的终极梦想.然而在当下,随着中概股在美国股市股价的不断走低.中国赴美上市企业私有化速度的加快,大众才发现,原来美国股市并不是那么好混的.但不管怎样,赴美上市始终是一种荣耀. ...
- C++走向远洋——60(项目四、立体类族共有的抽象类)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- .Net Core中使用ExceptionFilter
.Net Core中有各种Filter,分别是AuthorizationFilter.ResourceFilter.ExceptionFilter.ActionFilter.ResultFilter. ...
- linux svn 安装(支持http访问)
1.安装svn yum install -y subversion 2.查看svn版本 svn --version 3.创建仓库 mkdir -p /opt/java/repos cd /opt/ja ...
- Web环境从Apache转Nginx后页面报404错误
问题原因: Apache支持伪静态规则在项目的入口目录有个.htaccess文件,Apache默认识别此文件内容, 但是Nginx不识别.htaccess文件,导致伪静态规则失效,从而无法解析url地 ...
- vue組件自学
Vue组件 什么是组件? 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添 ...
- npm发布包的那些事
npm发包的那些事 最近一直在研习关于node的知识,发布包虽然是最基础的一点,但由于一些地方的不注意很容易发生错误,我整理了我可能出现过的一些发布包的过程中的一些error,现在分享给大家: 正确的 ...
- SPI总线传输的4种模式
概述 在芯片的资料上,有两个非常特殊的寄存器配置位,分别是 CPOL (Clock POlarity)和 CPHA (Clock PHAse). CPOL配置SPI总线的极性 CPHA配置SPI总线的 ...
- 【Python challenge】通关代码及攻略(0-11)
前言: 最近找到一个有关python的游戏闯关,这是游戏中的思考及通关攻略 最开始位于:http://www.pythonchallenge.com/pc/def/0.html 第0关 题目分析 提示 ...
- 安卓 打飞机 app 开发 第一篇
先上效果图 其实,当时刚买 htc G8 的时候(那时北京的房价还是6千一平),安卓2.1 ,2.3 的时候就已经有安卓方面的开发的兴趣,但后来就没有弄过... today 突然想起来,手机上连个游戏 ...