文章插图
心跳就是靠轮训,无论是服务端,还是客户端比如GCM等 。保活机制会在不同的应用场景进行动态的切换,比如程序唤起和在后台,轮训的策略是不一样的 。
Netty内置通过增加IdleStateHandler产生IDLE事件进行便捷的心跳控制 。你要处理的,就是心跳超时的逻辑,比如延迟重连 。但它的轮训时间是固定的,无法动态修改,高级功能需要自己定制 。
在一些客户端比如Android,频繁心跳的唤起会浪费大量的网络和电量,它的心跳策略会更加复杂一些 。
边界优雅退出机制
Java的优雅停机通常通过注册JDK ShutdownHook来实现 。
Runtime.getRuntime().addShutdownHook();一般通过kill -15进行java进程的关闭,以便在进程死亡之前进行一些清理工作 。
注意:kill -9 会立马杀死进程,不给遗言的机会,比较危险 。虽然netty做了很多优雅退出的工作,通过EventLoopGroup的shutdownGracefully方法对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 unlimitedroot soft nproc unlimited记得清理掉/etc/security/limits.d/*下的配置
网络优化
打开/etc/sysctl.conf,添加配置
然后执行,使用sysctl生效
#单个进程可分配的最大文件数fs.nr_open=2097152#系统最大文件句柄数fs.file-max = 1048576#backlog 设置net.core.somaxconn=32768net.ipv4.tcp_max_syn_backlog=16384net.core.netdev_max_backlog=16384#可用知名端口范围配置net.ipv4.ip_local_port_range='1000 65535'#TCP Socket 读写 Buffer 设置net.core.rmem_default=262144net.core.wmem_default=262144net.core.rmem_max=16777216net.core.wmem_max=16777216net.core.optmem_max=16777216net.ipv4.tcp_rmem='1024 4096 16777216'net.ipv4.tcp_wmem='1024 4096 16777216'#TCP 连接追踪设置net.nf_conntrack_max=1000000net.netfilter.nf_conntrack_max=1000000net.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
推荐阅读
- Java 编写基于 Netty 的 RPC 框架
- 什么样的枕芯比较好
- 排大便最佳时间是什么时候?
- 白领|2022年的四分之一已经过完了!距离我们年初定的目标还远吗?
- 钉钉使用评测 钉钉电脑版怎么下载
- 小孩皮肤黑变白容易吗
- 飞猪酒店不确认怎么办 飞猪酒店不确认
- 银耳发黄好不好 银耳发黄是什么原因影响使用吗
- 手机侧面按键失灵?可以使用排除法查找原因,再进行有针对的维修
- iPhone 如何使用FaceTime中的 SharePlay功能