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

 

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处 。
在JAVA界,netty无疑是开发网络应用的拿手菜 。你不需要太多关注复杂的nio模型和底层网络的细节,使用其丰富的接口,可以很容易的实现复杂的通讯功能 。
和golang的网络模块相比,netty还是太过臃肿 。不过java类框架就是这样,属于那种离了IDE就无法存活的编码语言 。
最新的netty版本将模块分的非常细,如果不清楚每个模块都有什么内容,直接使用netty-all即可 。
单纯从使用方面来说,netty是非常简单的,掌握ByteBuf、Channel、Pipeline、Event模型等,就可以进行开发了 。你会发现面试netty相关知识,没得聊 。但Netty与其他开发模式很大不同,最主要的就是其异步化 。异步化造成的后果就是编程模型的不同,同时有调试上的困难,对编码的要求比较高,因为bug的代价与业务代码的bug代价不可同日而语 。
但从项目来说,麻雀虽小五脏俱全,从业务层到服务网关,以及各种技术保障,包括监控和配置,都是需要考虑的因素 。netty本身占比很小 。
使用Netty,我们到底在开发些什么?

文章插图
 
本文将说明使用netty开发,都关注哪些通用的内容,然后附上单机支持100w连接的linux配置 。本文并不关注netty的基础知识 。
协议开发网络开发中最重要的就是其通讯格式,协议 。我们常见的protobuf、json、avro、mqtt等,都属于此列 。协议有语法、语义、时序三个要素 。
使用Netty,我们到底在开发些什么?

文章插图
 
我见过很多中间件应用,采用的是redis协议,而后端落地的却是MySQL;也见过更多的采用mysql协议实现的各种自定义存储系统,比如proxy端的分库分表中间件、tidb等 。
我们常用的redis,使用的是文本协议;mysql等实现的是二进制协议 。放在netty中也是一样,实现一套codec即可(继承Decoder或Encoder系列) 。netty默认实现了DNS、haproxy、http、http2、memcache、mqtt、redis、smtp、socks、stomp、xml等协议,可以说是很全了,直接拿来用很爽 。
一个可能的产品结构会是这样的,对外提供一致的外观,核心存储却不同:
使用Netty,我们到底在开发些什么?

文章插图
 
文本协议在调试起来是比较直观和容易的,但安全性欠佳;而二进制协议就需要依赖日志、wireshark等其他方式进行分析,增加了开发难度 。传说中的粘包拆包,就在这里处理 。而造成粘包的原因,主要是由于缓冲区的介入,所以需要约定双方的传输概要等信息,netty在一定程度上解决了这个问题 。
每一个想要开发网络应用的同学,心里都埋了一颗重新设计协议的梦想种子 。但协议的设计可以说是非常困难了,要深耕相应业务,还要考虑其扩展性 。如没有特别的必要,建议使用现有的协议 。
连接管理功能做Netty开发,连接管理功能是非常重要的 。通信质量、系统状态,以及一些黑科技功能,都是依赖连接管理功能 。
使用Netty,我们到底在开发些什么?

文章插图
 
无论是作为服务端还是客户端,netty在创建连接之后,都会得到一个叫做Channel的对象 。我们所要做的,就是对它的管理,我习惯给它起名叫做ConnectionManager 。
管理类会通过缓存一些内存对象,用来统计运行中的数据 。比如面向连接的功能:包发送、接收数量;包发送、接收速率;错误计数;连接重连次数;调用延迟;连接状态等 。这会频繁用到java中concurrent包的相关类,往往也是bug集中地 。
但我们还需要更多,管理类会给予每个连接更多的功能 。比如,连接创建后,想要预热一些功能,那这些状态就可以参与路由的决策 。通常情况下,将用户或其他元信息也attach到连接上,能够多维度的根据条件筛选一些连接,进行批量操作,比如灰度、过载保护等,是一个非常重要的功能 。
管理后台可以看到每个连接的信息,筛选到一个或多个连接后,能够开启对这些连接的流量录制、信息监控、断点调试,你能体验到掌控一切的感觉 。
管理功能还能够看到系统的整个运行状态,及时调整负载均衡策略;同时对扩容、缩容提供数据依据 。
心跳检测应用协议层的心跳是必须的,它和tcp keepalive是完全不同的概念 。
应用层协议层的心跳检测的是连接双方的存活性,兼而连接质量,而keepalive检测的是连接本身的存活性 。而且后者的超时时间默认过长,完全不能适应现代的网络环境 。


推荐阅读