搭建生产级的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 ...
随机推荐
- Google Hacking --你真的会用Google吗?
你真的会用Google吗?Google Hacking提升工作效率 阅读本文需要6.66分钟 Google hacking,也叫作google dorking.如果在 Google 上搜索 Googl ...
- textarea 实现高度自动增长
有时候希望textarea 能够自动调整高度来适应输入的内容 网上看到了很多解决方案,比如动态创建一个隐藏的div,当用户输入的时候将textarea的内容绑定到div,由于div的高度会自动撑开,因 ...
- Jprofile解析dump文件使用详解
1 Jprofile简介 官网 下载对应的系统版本即可 性能查看工具JProfiler,可用于查看java执行效率,查看线程状态,查看内存占用与内存对象,还可以分析dump日志. 2 功能简介 选择a ...
- Flutter调研(2)-Flutter从安装到运行成功的一些坑
工作需要,因客户端有部分页面要使用flutter编写,需要QA了解一下flutter相关知识,因此,做了flutter调研,包含安装,基础知识与demo编写,第二部分是安装与环境配置. —— 在mac ...
- Ajax&Json案例
案例: * 校验用户名是否存在 1. 服务器响应的数据,在客户端使用时,要想当做json数据格式使用.有两种解决方案: 1. $.get(type):将最后一个参数type指定为"json& ...
- 深度解析互联网大厂面试难题自定义@EnableXX系列
深度解析互联网大厂面试难题自定义@EnableXX系列 其实是一个@Import的设计技巧 创建注解@EnableXX(任何名称注解都行,只是这个名字好一些) XXConfiguration类不能 ...
- Eureka 注册中心看这一篇就够了
服务注册中心是服务实现服务化管理的核心组件,类似于目录服务的作用,主要用来存储服务信息,譬如提供者 url 串.路由信息等.服务注册中心是微服务架构中最基础的设施之一. 在微服务架构流行之前,注册中心 ...
- node--CommonJS
1.CommonJS 1)弥补js没有标准的缺陷 2.Node模块 1)分为核心模块和用户自定义模块 2)我们可以把公共的功能抽离为一个单独的js文件作为一个模块 其中的成员和属性外界无法访问,若要设 ...
- 30分钟学会Objective-C
注: 本文首发于我的个人博客:https://evilpan.com/2019/04/05/objc-basics/ 请原谅我的标题党.但是如果你有其他语言的学习经验,要学习Objective-C的语 ...
- 在eclipse的Java类文件中,右上角出现大写字母A代表什么
代表这个文件(类)是一个抽象类abstract的第一个字母: