您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

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

时间:2019-09-02 11:19:28  来源:  作者:

 

原创:小姐姐味道(微信公众号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检测的是连接本身的存活性。而且后者的超时时间默认过长,完全不能适应现代的网络环境。

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

 

心跳就是靠轮训,无论是服务端,还是客户端比如GCM等。保活机制会在不同的应用场景进行动态的切换,比如程序唤起和在后台,轮训的策略是不一样的。

Netty内置通过增加IdleStateHandler产生IDLE事件进行便捷的心跳控制。你要处理的,就是心跳超时的逻辑,比如延迟重连。但它的轮训时间是固定的,无法动态修改,高级功能需要自己定制。

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

边界

优雅退出机制

Java的优雅停机通常通过注册JDK ShutdownHook来实现。

Runtime.getRuntime().addShutdownHook();

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

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

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

流量可能还会通过外层的路由持续进入,造成无效请求。我的通常做法是首先在外层路由进行一次本地实例的摘除,把流量截断,然后再进行netty本身的优雅关闭。这种设计非常简单,即使没有重试机制也会运行的很好,前提是在路由层需要提前暴露相关接口。

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

 

异常处理功能

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

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

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

功能限制

指令模式

网络应用就该干网络应用的事,任何通讯都是昂贵的。在

《Linux之《荒岛余生》(五)网络篇》

中,我们谈到百万连接的服务器,广播一个1kb消息,就需要1000M的带宽,所以并不是什么都可以放在网络应用里的。

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

指令模式还会让通讯系统的扩展性和稳定性得到保证。增加指令可以是配置式的,立即生效,服务端不需要编码重启。

稳定性保证

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

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

缓存可能是网络应用里用的最多的组件。jvm内缓存可以存储一些单机的统计数据,redis等存储一些全局性的统计和中间态数据。

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

 

网络应用中会大量使用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的上手成本小,死挖底层并不会产生太多收益。

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

作者简介:**小姐姐味道** (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,​进一步交流。​



Tags:Netty   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言在实现TCP长连接功能中,客户端断线重连是一个很常见的问题,当我们使用netty实现断线重连时,是否考虑过如下几个问题: 如何监听到客户端和服务端连接断开 ? 如何实现断线后重...【详细内容】
2021-12-24  Tags: Netty  点击:(12)  评论:(0)  加入收藏
这篇文章对于排查使用了 netty 引发的堆外内存泄露问题,有一定的通用性,希望对你有所启发 背景最近在做一个基于 websocket 的长连中间件,服务端使用实现了 socket.io 协议(基于...【详细内容】
2021-12-16  Tags: Netty  点击:(22)  评论:(0)  加入收藏
简介在之前的文章中,我们提到了在netty的客户端通过使用Http2FrameCodec和Http2MultiplexHandler可以支持多路复用,也就是说在一个连接的channel基础上创建多个子channel,通过...【详细内容】
2021-12-14  Tags: Netty  点击:(8)  评论:(0)  加入收藏
本系列为 Netty 学习笔记,本篇介绍总结Java NIO 网络编程。Netty 作为一个异步的、事件驱动的网络应用程序框架,也是基于NIO的客户、服务器端的编程框架。其对 Java NIO 底层...【详细内容】
2021-12-07  Tags: Netty  点击:(17)  评论:(0)  加入收藏
想要阅读Netty源码的同学,建议从GitHub上把源码拉下来,方便写注释、Debug调试哦~点我去下载! 先来看一个简单的Echo服务端程序,监听本地的9999端口,有客户端接入时控制台输出一句...【详细内容】
2021-10-22  Tags: Netty  点击:(45)  评论:(0)  加入收藏
相信很多人知道石中剑这个典故,在此典故中,天命注定的亚瑟很容易的就拔出了这把石中剑,但是由于资历不被其他人认可,所以他颇费了一番周折才成为了真正意义上的英格兰全境之王,亚...【详细内容】
2021-07-22  Tags: Netty  点击:(102)  评论:(0)  加入收藏
家纯 阿里技术 一 什么是 Netty? 能做什么? Netty 是一个致力于创建高性能网络应用程序的成熟的 IO 框架。 相比较与直接使用底层的 Java IO API,你不需要先成为网络专家就...【详细内容】
2021-06-23  Tags: Netty  点击:(136)  评论:(0)  加入收藏
客户端代码package com.huanfeng.test;import java.io.BufferedReader;import java.io.InputStreamReader;import java.net.URL;import java.net.URLConnection;import java...【详细内容】
2021-05-26  Tags: Netty  点击:(146)  评论:(0)  加入收藏
前言:作为一个刚踏入职场的实习生,我很幸运参加了某个政府项目,并且在项目中负责一个核心模块功能的开发,而不是从头到尾对数据库的crud。虽然我一直心里抱怨我的工作范围根本...【详细内容】
2021-05-24  Tags: Netty  点击:(231)  评论:(0)  加入收藏
要求1.群聊系统可以实现服务器端和客户端之间的数据简单通讯(非阻塞)2.通过系统可以实现多人群聊3.服务器端:可以监控用户上线,离线,并实现消息转发功能4.客户端:通过channel可...【详细内容】
2021-05-24  Tags: Netty  点击:(147)  评论:(0)  加入收藏
▌简易百科推荐
面向对象的特征之一封装 面向对象的特征之二继承 方法重写(override/overWrite) 方法的重载(overload)和重写(override)的区别: 面向对象特征之三:多态 Instanceof关键字...【详细内容】
2021-12-28  顶顶架构师    Tags:面向对象   点击:(2)  评论:(0)  加入收藏
一、Redis使用过程中一些小的注意点1、不要把Redis当成数据库来使用二、Arrays.asList常见失误需求:把数组转成list集合去处理。方法:Arrays.asList 或者 Java8的stream流式处...【详细内容】
2021-12-27  CF07    Tags:Java   点击:(3)  评论:(0)  加入收藏
文章目录 如何理解面向对象编程? JDK 和 JRE 有什么区别? 如何理解Java中封装,继承、多态特性? 如何理解Java中的字节码对象? 你是如何理解Java中的泛型的? 说说泛型应用...【详细内容】
2021-12-24  Java架构师之路    Tags:JAVA   点击:(5)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  小码匠和老码农    Tags:JVM调优   点击:(12)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  dingle    Tags:JDBC   点击:(13)  评论:(0)  加入收藏
Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的...【详细内容】
2021-12-23  JAVA小白    Tags:Java   点击:(11)  评论:(0)  加入收藏
Java从版本5开始,在 java.util.concurrent.locks包内给我们提供了除了synchronized关键字以外的几个新的锁功能的实现,ReentrantLock就是其中的一个。但是这并不意味着我们可...【详细内容】
2021-12-17  小西学JAVA    Tags:JAVA并发   点击:(11)  评论:(0)  加入收藏
一、概述final是Java关键字中最常见之一,表示“最终的,不可更改”之意,在Java中也正是这个意思。有final修饰的内容,就会变得与众不同,它们会变成终极存在,其内容成为固定的存在。...【详细内容】
2021-12-15  唯一浩哥    Tags:Java基础   点击:(17)  评论:(0)  加入收藏
1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友。2、解决方案这次其实是碰到了一个问题,一般的情况...【详细内容】
2021-12-15  软件老王    Tags:logback   点击:(19)  评论:(0)  加入收藏
本篇文章我们以AtomicInteger为例子,主要讲解下CAS(Compare And Swap)功能是如何在AtomicInteger中使用的,以及提供CAS功能的Unsafe对象。我们先从一个例子开始吧。假设现在我们...【详细内容】
2021-12-14  小西学JAVA    Tags:JAVA   点击:(22)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条