使用Netty,咱们到底在开发些什么?

在java界,netty无疑是开发网络应用的拿手菜。你不须要太多关注复杂的nio模型和底层网络的细节,使用其丰富的接口,能够很容易的实现复杂的通信功能。java

和golang的网络模块相比,netty仍是太过臃肿。不过java类框架就是这样,属于那种离了IDE就没法存活的编码语言。mysql

最新的netty版本将模块分的很是细,若是不清楚每一个模块都有什么内容,直接使用netty-all便可。linux

单纯从使用方面来讲,netty是很是简单的,掌握ByteBuf、Channel、Pipeline、Event模型等,就能够进行开发了。你会发现面试netty相关知识,没得聊。但Netty与其余开发模式很大不一样,最主要的就是其异步化。异步化形成的后果就是编程模型的不一样,同时有调试上的困难,对编码的要求比较高,由于bug的代价与业务代码的bug代价不可同日而语。golang

但从项目来讲,麻雀虽小五脏俱全,从业务层到服务网关,以及各类技术保障,包括监控和配置,都是须要考虑的因素。netty自己占比很小。 本文将说明使用netty开发,都关注哪些通用的内容,而后附上单机支持100w链接的linux配置。本文并不关注netty的基础知识。面试

协议开发

网络开发中最重要的就是其通信格式,协议。咱们常见的protobuf、json、avro、mqtt等,都属于此列。协议有语法、语义、时序三个要素。 redis

我见过不少中间件应用,采用的是redis协议,然后端落地的倒是mysql;也见过更多的采用mysql协议实现的各类自定义存储系统,好比proxy端的分库分表中间件、tidb等。sql

咱们经常使用的redis,使用的是文本协议;mysql等实现的是二进制协议。放在netty中也是同样,实现一套codec便可(继承Decoder或Encoder系列)。netty默认实现了dns、haproxy、http、http二、memcache、mqtt、redis、smtp、socks、stomp、xml等协议,能够说是很全了,直接拿来用很爽。编程

一个可能的产品结构会是这样的,对外提供一致的外观,核心存储却不一样: 文本协议在调试起来是比较直观和容易的,但安全性欠佳;而二进制协议就须要依赖日志、wireshark等其余方式进行分析,增长了开发难度。传说中的粘包拆包,就在这里处理。而形成粘包的缘由,主要是因为缓冲区的介入,因此须要约定双方的传输概要等信息,netty在必定程度上解决了这个问题。json

每个想要开发网络应用的同窗,内心都埋了一颗从新设计协议的梦想种子。但协议的设计能够说是很是困难了,要深耕相应业务,还要考虑其扩展性。如没有特别的必要,建议使用现有的协议。后端

链接管理功能

作Netty开发,链接管理功能是很是重要的。通讯质量、系统状态,以及一些黑科技功能,都是依赖链接管理功能。 不管是做为服务端仍是客户端,netty在建立链接以后,都会获得一个叫作Channel的对象。咱们所要作的,就是对它的管理,我习惯给它起名叫作ConnectionManager

管理类会经过缓存一些内存对象,用来统计运行中的数据。好比面向链接的功能:包发送、接收数量;包发送、接收速率;错误计数;链接重连次数;调用延迟;链接状态等。这会频繁用到java中concurrent包的相关类,每每也是bug集中地。

但咱们还须要更多,管理类会给予每一个链接更多的功能。好比,链接建立后,想要预热一些功能,那这些状态就能够参与路由的决策。一般状况下,将用户或其余元信息也attach到链接上,可以多维度的根据条件筛选一些链接,进行批量操做,好比灰度、过载保护等,是一个很是重要的功能。

管理后台能够看到每一个链接的信息,筛选到一个或多个链接后,可以开启对这些链接的流量录制、信息监控、断点调试,你能体验到掌控一切的感受。

管理功能还可以看到系统的整个运行状态,及时调整负载均衡策略;同时对扩容、缩容提供数据依据。

心跳检测

应用协议层的心跳是必须的,它和tcp keepalive是彻底不一样的概念。

应用层协议层的心跳检测的是链接双方的存活性,兼而链接质量,而keepalive检测的是链接自己的存活性。并且后者的超时时间默认过长,彻底不能适应现代的网络环境。 心跳就是靠轮训,不管是服务端,仍是客户端好比GCM等。保活机制会在不一样的应用场景进行动态的切换,好比程序唤起和在后台,轮训的策略是不同的。

Netty内置经过增长IdleStateHandler产生IDLE事件进行便捷的心跳控制。你要处理的,就是心跳超时的逻辑,好比延迟重连。但它的轮训时间是固定的,没法动态修改,高级功能须要本身定制。

在一些客户端好比Android,频繁心跳的唤起会浪费大量的网络和电量,它的心跳策略会更加复杂一些。

边界

优雅退出机制

Java的优雅停机一般经过注册JDK ShutdownHook来实现。

Runtime.getRuntime().addShutdownHook();

通常经过kill -15进行java进程的关闭,以便在进程死亡以前进行一些清理工做。

注意:kill -9 会立马杀死进程,不给遗言的机会,比较危险。

虽然netty作了不少优雅退出的工做,经过EventLoopGroupshutdownGracefully方法对nio进行了一些状态设置,但在不少状况下,这还不够多。它只负责单机环境的优雅关闭。

流量可能还会经过外层的路由持续进入,形成无效请求。个人一般作法是首先在外层路由进行一次本地实例的摘除,把流量截断,而后再进行netty自己的优雅关闭。这种设计很是简单,即便没有重试机制也会运行的很好,前提是在路由层须要提早暴露相关接口。

异常处理功能

netty因为其异步化的开发方式,以及其事件机制,在异常处理方面就显得异常重要。为了保证链接的高可靠性,许多异常须要静悄悄的忽略,或者在用户态没有感知。

netty的异常会经过pipeline进行传播,因此在任何一层进行处理都是可行的,但编程习惯上,习惯性抛到最外层集中处理。

为了最大限度的区别异常信息,一般会定义大量的异常类,不一样的错误会抛出不一样的异常。发生异常后,能够根据不一样的类型选择断线重连(好比一些二进制协议的编解码紊乱问题),或者调度到其余节点。

功能限制

指令模式

网络应用就该干网络应用的事,任何通信都是昂贵的。在《Linux之《荒岛余生》(五)网络篇》中,咱们谈到百万链接的服务器,广播一个1kb消息,就须要1000M的带宽,因此并非什么均可以放在网络应用里的。

一个大型网络应用的合理的思路就是值发送相关指令。客户端在收到指令之后,经过其余方式,好比http,进行大型文件到获取。不少IM的设计思路就是如此。

指令模式还会让通信系统的扩展性和稳定性获得保证。增长指令能够是配置式的,当即生效,服务端不须要编码重启。

稳定性保证

网络应用的流量通常都是很是大的,并不适合全量日志的开启。应用应该只关注主要事件的日志,关注异常状况下的处理流程,日志要打印有度。

网络应用也不适合调用其余缓慢的api,或者任何阻塞I/O的接口。一些实时的事件,也不该该经过调用接口吐出数据,能够走高速mq等其余异步通道。

缓存多是网络应用里用的最多的组件。jvm内缓存能够存储一些单机的统计数据,redis等存储一些全局性的统计和中间态数据。 网络应用中会大量使用redis、kv、高吞吐的mq,用来快速响应用户请求。总之,尽可能保持通信层的清爽,你会省去不少忧虑。

单机支持100万链接的Linux配置

单机支持100万链接是可行的,但带宽问题会成为显著的瓶颈。启用压缩的二进制协议会节省部分带宽,但开发难度增长。

《LWP进程资源耗尽,Resource temporarily unavailable》中提到的ES配置同样,优化都有相似的思路。这份配置,能够节省你几天的时间,请收下!

操做系统优化

更改进程最大文件句柄数

ulimit -n 1048576

修改单个进程可分配的最大文件数

echo 2097152 > /proc/sys/fs/nr_open

修改/etc/security/limits.conf文件

*   soft nofile  1048576
*   hard nofile 1048576
*   soft nproc unlimited
root soft nproc unlimited

记得清理掉/etc/security/limits.d/*下的配置

网络优化

打开/etc/sysctl.conf,添加配置 而后执行,使用sysctl生效

#单个进程可分配的最大文件数
fs.nr_open=2097152

#系统最大文件句柄数
fs.file-max = 1048576

#backlog 设置
net.core.somaxconn=32768
net.ipv4.tcp_max_syn_backlog=16384
net.core.netdev_max_backlog=16384

#可用知名端口范围配置
net.ipv4.ip_local_port_range='1000 65535'

#TCP Socket 读写 Buffer 设置
net.core.rmem_default=262144
net.core.wmem_default=262144
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.core.optmem_max=16777216
net.ipv4.tcp_rmem='1024 4096 16777216'
net.ipv4.tcp_wmem='1024 4096 16777216'

#TCP 链接追踪设置
net.nf_conntrack_max=1000000
net.netfilter.nf_conntrack_max=1000000
net.netfilter.nf_conntrack_tcp_timeout_time_wait=30

#TIME-WAIT Socket 最大数量、回收与重用设置
net.ipv4.tcp_max_tw_buckets=1048576

# FIN-WAIT-2 Socket 超时设置
net.ipv4.tcp_fin_timeout = 15

总结

netty的开发工做并不集中在netty自己,更多体如今保证服务的高可靠性和稳定性上。同时有大量的工做集中在监控和调试,减小bug修复的成本。

深刻了解netty是在系统遇到疑难问题时可以深刻挖掘进行排查,或者对苛刻的性能进行提高。但对于广大应用开发者来讲,netty的上手成本小,死挖底层并不会产生太多收益。

它只是个工具,你还能让它怎样啊。 0.jpeg

相关文章
相关标签/搜索