《干翻Netty》, 写一个底层通信框架需要考虑哪些?

原创
2021/12/16 15:04
阅读数 200

大家好,我是yes。

Netty系列本来双十一之前就要写的...硬生生的拖到了现在,这次不鸽了!这个系列的目的非常朴实,就是想全方位了解下 Netty,为我们的简历添砖加瓦~

为此,我已经铺垫了几篇了:

这篇算是 Netty 系列的开篇,开篇不会很快进入细节,开篇需要从高纬度入手,总览全局

我有个习惯,在新学一个框架的时候,在有一定的基础下,我会闭上眼睛思考这个框架应该需要哪些核心要点。

拿 Netty 举例,我会假设老板给我个任务,要我写一个底层通信框架,我要怎么写?都有哪些方面需要考虑

通过这种驱动式自我提问,来推动自己不得不去思考,被动让脑子转!这样会让你理解地更深刻。

下面我们一起来思考下这个问题。

写一个底层通信框架需要考虑哪些?

关于通信,我第一个想到的就是网络协议,好在一些协议底层都已经帮我们实现,但是要通信还是避免不了和底层打交道。比如,要调用操作系统的接口来发送数据给远程,如果要我们去实现还得去了解操作系统的各种接口,感觉有点麻烦。

但好在,这样底层的交互,身为一门语言肯定是已经提供了封装的,对于 Java 而言提供了 NIO。

所以,通信的一些基本操作,包括创建 socket、建立连接、发送消息、接收消息等等,这些 NIO 都提供了。

这样岂不是直接用 Java NIO 就行了?

用肯定是要用的,但是这种语言类库提供的接口,需要给予上层更多自由的配置,也就是它能提供精细化地调用,但是对于通常的使用而言过于复杂。

就好下面这张图,对于已经深耕的专业人员来说,可能极好。

但是对于普通使用者而言,上手成本就太高了。简而言之,就是封装的不够完美,不够简单。

我们追求的是仪表盘只需暴露几个键,只要按几个键应用即可成功的运行,所以我们需要基于 Java NIO 做封装,把一些复杂的配置隐藏起来,对外暴露出更加易用的接口。

所以,我们的第一个目标已经明确了,利用 Java NIO 提供的能力并基于它做封装,尽量简化配置,易于使用。(其实框架都这样,例如 Mybatis 之类的,还是得基于 JDBC 的能力,在此之上封装)

大体目标有了,然后得丰富一下功能性。

由于网络通信都是字节流,所以我们还要提供编解码的支持,且需要支持各种协议,毕竟身为一个框架需要供各种团队使用,每个团队涉及的通信协议可能有所不同,因此框架需要尽可能的支持市面上常见的协议,比如 HTTP、DNS 等等,当然也要方便的定制自定义协议。

对了,还需要考虑粘包和拆包等问题,支持分隔符切分、固定长度等等,给予“客户”更多方便的选择!

实现上面这些,一些基本的通信需求满足了,然后再考虑性能。

身为一个网络通信框架,我们需要考虑连接的管理,毕竟资源是有限的,所以合理的连接数很重要,因此我们需要提供心跳、检查空闲连接等功能来管理连接。

还有 I/O 模型,现在这个“行情”不说了,直接多路复用,用更少的线程处理更多的请求, hold 住海量连接。等啥时候 Linux 完美支持 AIO 了再上个 AIO,不过 Linux 提供了 epoll ,所以如果服务是跑在 Linux 上的就用 epoll,反之用 select。

对了,网上经常还会提到零拷贝,这个肯定是要的,比如发送一些文件的时候直接利用零拷贝减少拷贝次数,并且还能用 DirectBuffer 将数据放置堆外,省去了堆内外的一次拷贝,提升性能。

当然对应的还得需要做好内存管理,这个我想可以参考参考 Linux 的伙伴系统。

关于线程模型,也得研究研究,例如 accept 线程与 reactor 线程(I/O线程)与业务处理线程的编排等等,在大流量下合理的线程模型会减少线程切换次数,提高性能,这很关键。

然后一个框架想要易用,不仅要适配不同团队的不同需求,还需方便适配同一团队的需求变更。这就需要框架必须要提供十分方便的定制化、插件化功能,这又该怎么设计?责任链模式就适合这个,配合事件驱动,好像挺完美的。

我个人认为,身为一个框架,提供诸多开箱即用的功能、接口易用、性能好、易扩展,那简直就是完美!

总之,通信框架的思考可以从功能出发:配置启动服务、建立连接、接收数据、处理业务、发送数据、关闭连接、关闭服务。从这条主线入手,分别考虑上述说的,易用的接口、I/O 模型、编解码、开箱即用的协议支持、线程模型、连接管理、内存管理等。

综上,这就是我个人认为实现一个底层通信框架要思考的一些核心点,当然还有很多细节和一些锦上添花的功能,这还得再细细的盘一盘。

可以看到,要做一款通信框架,并没有那么简单,有很多需要考虑,这也是为什么那么多中间件底层通信框架不自己实现,而是都利用 Netty 的原因。

因为 Netty 将这些都实现了。

什么是Netty?

它是高性能 Java 网络通信的底层框架,可能你听过的很多中间件底层通信框架用的都是它,例如 RocketMQ、Dubbo、Elasticsearch、Cassandra等。

它为什么这么流行?为什么这么多中间件都在它之上构建?

易用

对 Java 的 NIO 进行了封装,屏蔽了 NIO 使用的复杂性,简化了网络通信的开发。

且支持众多协议,不仅仅 HTTP、HTTP2、DNS、Redis 协议等等。

网络编程需要考虑粘包和拆包问题,连接的管理,编解码的处理,Netty都为你定制好了,开箱即用。

还提供的内存泄漏检测,IP过滤、流量整型等高级功能。

性能

良好的I/O模型。

Netty 基于 Java NIO 封装实现了 I/O 多路复用,可由一个线程轮询多个底层 channel,减少了线程资源,也减少了多线程切换带来的开销,能更好的处理海量连接,提升系统的性能。

在 Linux 环境下也会用更优的 epoll 模型。

运用零拷贝技术。不仅利用操作系统提供的零拷贝,也基于堆外内存省了一次 JVM 堆内外之间的拷贝。

对象池技术,通过对象的复用,避免频繁创建和销毁带来的开销。

扩展性

基于事件驱动模型,将业务实现剥离成一个个 ChannelHandler ,利用责任链模式,可以很好的根据不同业务进行扩展,使用者只需要实现相关的 ChannelHandler 即可,框架与业务隔离

可以根据情况配置线程模型,例如主从 Reactor ,主多从 Reactor 等等。

最后

这篇,只是从一个很高的纬度来谈谈一个底层网络通信框架的实现需要包含哪些核心点,以及 Netty 的一个很粗的概况,等之后系列完结了之后,再来一个详细的全局总结。

下篇,开始总览 Netty 的一些核心组件。

这次的 Netty 系列,我们一起学完后,我相信 Netty 或许能成为你以后面试的加分项,因为它不仅涵盖的知识面广,且有很多精妙的设计。

欢迎关注我的公众号【yes的练级攻略】

我是yes,从一点点到亿点点,我们下篇见~

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部