详解netty长连接网关请求处理模型

2023-10-27

想要支持海量的客户端请求,首先要有一套高效的请求处理模型。本文以开源项目SONA为例,详解如何基于netty设计请求处理模型,帮助读者动手实践。本文最后附上开源项目地址。


背景

Sona 平台是一个搭建语音房产品的全端解决方案,包含了房间管理、实时音视频、房间IM、长连接网关等能力。其中最基础核心的就是长连接网关,作为网关,首先要支持处理海量的客户端请求,要做到这一点,需要设计一套稳定高效的请求处理模型。


一、Netty 处理模型

Netty 使用 主从Reactor模型

bossGroup 负责处理 accept 事件 , workerGroup 负责处理 read 、write 事件。

其中 ChannelPipeline 是一个双向链表,netty 里面定义了十几种事件,触发之后会顺序调用所有 ChannelHandler 的指定方法,ChannelHandler的调用都是由 workerGroup中的同一个 eventloop 线程执行,不存在线程之间的切换。 

这种无锁化的设计,避免了上下文切换,在海量请求的情况下能提供很高的性能。但是也存在风险,如果执行某个 ChannelHandler 出现了阻塞,会拖累这个 eventloop 线程所负责的其他请求。

在实际场景中,ChannelHandler里面一般都会执行一些 IO 操作,比如RPC调用,MQ等,无法保证不会出现阻塞的情况。所以很多高性能的分布式框架中都会使用三层处理模型,额外增加一个业务线程池,将耗时的IO操作放在这个业务线程池里面执行,这样就不会阻塞 workerGroup 中的线程了。

二、sona-gateway 处理模型

1、NettyServerHandler

pipeline 中除了 encode 和 decode ,只实现了一个 NettyServerHandler ,避免过多的handler 影响执行效率。

NettyServerHandler 里面使用装饰器模式实现了不同分工的 handler

AccessChannelHandler 基于 IP 的权限校验,不符合的连接直接拒绝
CatReportChannelHandler cat 数据打点上报
IdleChannelHandler 心跳和探测消息、握手等任务处理
DispatchChannelHandler 线程池分发请求
MercuryServerHandler 最上层的业务数据处理 handler

在上面也提到过,netty 里面的 ChannelHandler 有十几种事件,但对于我们来说,其实只需要关注其中的几种事件。因此,在NettyServerHandler中做了一层映射

channelActive connect 建立连接
channelInactive disconnect 断开连接
channelRead receive 读取到数据
write send 写入数据
exceptionCaught caught 异常捕获

NettyChannel 是我对 netty 底层 channel 的封装,业务层直接操作 NettyChannel,无需关心底层channel的处理,屏蔽了netty的使用细节。里面实现了对连接的维护管理以及消息发送的优化

2、MercuryServerHandler

MercuryServerHandler 中会根据请求中的 Command 命令,将当前请求路由到对应的业务 handler 中处理,并处理 request-response 模型。

开源版本只提供了登录、房间相关的处理器,详细可见github 的wiki 文档:

https://github.com/BixinTech/sona/wiki/%E9%95%BF%E8%BF%9E%E6%8E%A5%E7%BD%91%E5%85%B3#%E9%95%BF%E9%93%BE-command-%E8%AF%B7%E6%B1%82

用户可以基于gateway中提供的扩展,自定义请求处理器,实现自己的业务。

3、DispatchChannelHandler

这里着重介绍一下 DispatchChannelHandler ,前面说了这个 handler 是用于线程池分发请求的。

一般情况下,其实用 Jdk里面提供的线程池就可以了,比如说 Dubbo ,通过 spi 的方式提供了4种线程池,服务端默认使用 fixed ,客户端默认使用 cached。但底层还是直接使用的ThreadPoolExecutor

对于 IM 场景下,需要严格保证单个 channel 的处理顺序,但不同channel 之间可以不用保证顺序。

所以这里我是自己实现了一个 线程池 OrderedChannelExecutor

  1. 每个channel 都会生成一个 channelId (这里并没有使用 Netty里面默认的 id,而是通过一定规则生成的,主要是因为某些业务处理上的需要)

  2. 通过对 channelId 做一致性哈希,将这个channel 中的所有请求都路由到同一个 MpscQueue 里面。(MpscQueue 是 JCTools里面提供的 多生产者单消费者模式的 lock free 队列,能保证并发安全并且性能极高,Netty 底层使用的队列就是这个)

  3. MpscQueue 会从线程池里挑选一个线程去执行任务,只有当前任务处理完成,才会再从队列里 poll 下一个任务执行

  4. 只要MpscQueue 里面有数据,就会一直霸占这个线程,等队列的任务都执行完了,才会将它放回线程池中

目前 MpscQueue 和线程数量是 1:1 ,每个队列都能拿到一个线程,不需要任何等待

设计的时候,没有参考 netty eventloop 那样将 Selector 和线程 强绑定,因为我觉得线程是比较珍贵的资源,生产机器的配置是4核8g,线程多了性能也不一定能提升,而队列相对来说还好,只是耗点内存,项目中在节省内存方面也做了很多优化,大量使用池化技术,8g内存完全足够了,所以队列数量是可以大于线程数量的。

当时想着后面实现一个分级队列,支持队列按照优先级划分,优先级越高则有更高的概率优先执行,优先级低的在系统负载过大时,则允许延迟处理、丢弃或者快速失败 。不过之前压测,单机可以支持的 qps 远超预期,目前业务上还远远没有达到这种量级,就暂时搁置了。


总结

本文详细介绍了SONA长连接网关中的请求处理模型,在后续的系列文章中会对网关中的其他技术细节进行详细的介绍。

目前sona已经在比心的github仓库上开源,仓库地址:

GitHub - BixinTech/sona: Sona 平台是一个搭建语音房产品的全端解决方案,包含了房间管理、实时音视频、房间IM、长连接网关等能力。Sona 平台是一个搭建语音房产品的全端解决方案,包含了房间管理、实时音视频、房间IM、长连接网关等能力。 - GitHub - BixinTech/sona: Sona 平台是一个搭建语音房产品的全端解决方案,包含了房间管理、实时音视频、房间IM、长连接网关等能力。https://github.com/BixinTech/sona

欢迎你访问我们的项目,有任何想交流的想法可以留言联系我们。

往期阅读:

从0到1快速了解netty长连接网关协议_聊天室程序猿的博客-CSDN博客

比心聊天室的架构演进_聊天室程序猿的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详解netty长连接网关请求处理模型 的相关文章

随机推荐

  • 计算机视觉服务系统

    tornado教程HTTP教程 Eureka教程Eureka1Eureka2
  • Colossal-AI的安装

    最近在学习stable diffusion model 但是这个模型成本比较高 作为低端学习者 借助colossal ai加速训练 即能满足显卡要求又能节约时间 Colossal AI 是一个集成的大规模深度学习系统 具有高效的并行化技术
  • 二叉树变成搜索二叉树

    给你一个普通的二叉树 把它变成搜索二叉树 要求不改变这个树的结构 例如 给你如下二叉树 10 2 7 8 4 结果是 8 4 10 2 7 思路 1 中序遍历该二叉树 把结果存在临时数组 arr 中 2 对 arr 进行排序 3 把 arr
  • C++(11):true_type, false_type

    true type和false type是integral constant实例化的别名 C 11 integral constant 风静如云的博客 CSDN博客 template
  • matlab机械手ikine函数,matlab机器人工具箱10.1(有函数说明)

    实例简介 机器人工具箱10 1版 有例子可以学习 希望对大家有所帮助 实例截图 核心代码 robot工具箱 V10 1有例子 robot工具箱10 1及例子 matlab robot V10 1工具箱 pdf rvctools common
  • OpenXml操作Word的一些操作总结.无word组件生成word.

    OpenXml相对于用MS提供的COM组件来生成WORD 有如下优势 1 相对于MS 的COM组件 因为版本带来的不兼容问题 及各种会生成WORD半途会崩溃的问题 2 对比填满一张30多页的WORD来说 包含图 表等 用COM组件来生成会占
  • 【笔记】AOE网与关键路径

    AOE网 关键路径 求关键路径的算法实现 AOE网是以边表示活动的有向无环网 在AOE网中 具有最大路径长度的路径称为关键路径 关键路径表示完成工程的最短工期 1 AOE网 AOE网是一个带权的有向无环图 其中用顶点表示事件 弧表示活动 权
  • PCL生成线段点云

    生成三角形 生成平行四边形 生成凸包 pcl 生成线段点云 pcl官方有生成球体 圆柱体 圆锥体的相关函数 似乎没有生成线段的函数 正好有需要 所以自己写了两个 分别是根据数量和步长生成 原理 原理很简单 已知两个三维点p1 p2 求出方向
  • vue中使用高德地图marker标记点的setLabel,在不同层级下控制显示隐藏

    vue中使用高德地图marker标记点的setLabel 在不同层级下控制显示隐藏 设置点标注的文本标签 marker setLabel offset new AMap Pixel 1 0 设置文本标注偏移量 content div nam
  • 全局获取Context的技巧(再也不要为获取Context而感到烦恼)

    前言 Android提供了一个Application类 每当应用程序启动的时候 系统就会自动将这个类进行初始化 而我们可以定制一个自己的Application类 以便管理程序内的一些全局状态信息 比如说全局Context 定制自己的Appl
  • SaaS与本地部署 路在何方?

    了解云计算的一定都听过四个 高大上 的概念 On Premises 本地部署 IaaS 基础设施及服务 PaaS 平台即服务 和SaaS 软件即服务 这几个术语并不好理解 ServiceHot 旗下现产品有 ServiceHot ITSOM
  • Issues with peer dependencies found

    peer dependencies 默认存在的依赖 通常在开发组件和插件的时候用到 表示这些依赖不用下载 项目的仓库里有 例子 package json peer dependencies react 问题背景 今天安装一些依赖 报了这个错
  • Linux驱动编程(分层分离编程思想)

    1 面向对象 字符设备驱动程序抽象出一个 file operations 结构体 我们写的程序针对硬件部分抽象出 led operations 结构体 2 分层 上层实现硬件无关的操作 比如注册字符设备驱动 leddrv c 下层实现硬件相
  • @Autowired 和 @Resource 分别什么时候使用比较好

    Autowired 和 Resource 都是用于依赖注入的注解 但是它们有一些不同的使用场景 Autowired 是 Spring 框架提供的注解 它可以自动装配一个 Bean 可以根据类型进行匹配 也可以根据名称进行匹配 当有多个 Be
  • 数制转换(数据结构课程设计C语言版)

    define CRT SECURE NO WARNINGS include
  • 51单片机——定时器

    51单片机 定时器 为什么使用定时器 定时器原理 定时器设置 中断配置 源代码 为什么使用定时器 之前我们的led灯每隔1s循环左移点亮的时候 使用的定时方法是在c程序执行若干次空循环 这样会耗费很多cpu资源 因为空轮询 本篇博客将使用5
  • epoll使用(服务端代码讲解)

    下面这段代码是一个回射服务器 它会把客户端发送给它的信息再返回给客户端 include
  • Python的深浅拷贝

    目录 一 可变对象和不可变对象 二 概念 三 深浅拷贝 1 浅拷贝 2 深拷贝 一 可变对象和不可变对象 可变类型 列表 字典 集合 不可变类型 整数 小数 复数 字符串 元组 二 概念 是指向引用 浅拷贝 只拷贝父对象 不拷贝子对象 深拷
  • 数据库初始化过程

    从数据文件到内存的初始化过程 SQL gt startup mount ORACLE 例程已经启动 Total System Global Area 1970937856 bytes Fixed Size 2191096 bytes Var
  • 详解netty长连接网关请求处理模型

    想要支持海量的客户端请求 首先要有一套高效的请求处理模型 本文以开源项目SONA为例 详解如何基于netty设计请求处理模型 帮助读者动手实践 本文最后附上开源项目地址 背景 Sona 平台是一个搭建语音房产品的全端解决方案 包含了房间管理