龙空技术网

不要成为PPT架构师!消息队列系统中如何使用Netty和Zookeeper

南絮爸爸 60

前言:

此刻你们对“nettynginx游戏框架”都比较关心,你们都需要分析一些“nettynginx游戏框架”的相关文章。那么小编也在网络上网罗了一些对于“nettynginx游戏框架””的相关文章,希望小伙伴们能喜欢,我们一起来学习一下吧!

网络模型

Reactor 介绍

Reactor:基于多路复用的事件响应网络编程模型。

【多路复用】

多个连接复用同一个阻塞对象,例如 Java 的 Selector、epoll 的 epoll_fd(epoll_create 函数创建)。

【事件响应】

不同的事件分发给不同的对象处理,Java 的事件有 OP_ACCEPT、OP_CONNECT、OP_READ、OP_WRITE。

【优缺点】

1. 实现比传统网络模型要复杂;

2. 支持海量连接。

Reactor 模式1 - 单 Reactor 单进程/单线程

【优点】

1. 实现简单,无进程通信,无线程互斥和通信;

2. 无上下文切换,某些场景下性能可以做到很高。

【缺点】

1. 只有一个进程,无法发挥多核 CPU 的性能;只能采取部署多个系统来利用多核 CPU,但这样会带来运维复杂度;

2. Handler 在处理某个连接上的业务时,整个进程无法处理其他连接的事件,可能导致性能瓶颈。

【案例】

Redis

【流程】

1. Reactor 对象通过 select 监控连接事件,收到事件后通过 dispatch 进行分发。

2. 如果是连接建立的事件,则由 Acceptor 处理,Acceptor 通过 accept 接受连接,并创建一个 Handler 来处理连接后续的各种事件。

3. 如果不是连接建立事件,则 Reactor 会调用连接对应的 Handler(第2步中创建的 Handler)来进行响应。Handler 会完成 read → 业务处理 → send的完整业务流程。

Reactor 模式2 - 单 Reactor 多线程

【优点】

充分利用了多核 CPU 的优势,性能高。

【缺点】

1. 多线程数据共享和访问比较复杂;

2. Reactor 承担所有事件的监听和响应,只在主线程中运行,瞬时高并发时会成为性能瓶颈。

【流程】

1. 主线程中,Reactor 对象通过 select 监控连接事件,收到事件后通过 dispatch 进行分发。

2. 如果是连接建立的事件,则由 Acceptor 处理,Acceptor 通过 accept 接受连接,并创建一个 Handler 来处理连接后续的各种事件。

3. 如果不是连接建立事件,则 Reactor 会调用连接对应的 Handler(第2步中创建的 Handler)来进行响应。

4. Handler 只负责响应事件,不进行业务处理;Handler 通过 read 读取到数据后,会发给 Processor 进行业务处理。

5. Processor 会在独立的子线程中完成真正的业务处理,然后将响应结果发给主进程的 Handler 处理;Handler 收到响应后通过 send 将响应结果返回给 client。

Reactor 模式3 - 多 Reactor 多进程/线程

【优点】

1. 充分利用了多核 CPU 的优势,性能高;

2. 实现简单,父子进程(线程)交互简单,subReactor子进程(线程)间无互斥共享或通信。

【缺点】

没有明显的缺点,虽然自己实现会很复杂,但是目前已经有非常成熟的开源方案。

【案例】

Memcached、Netty、Nginx 等,

注意:实现细节都有一些差异,例如Memcached 用了事件队列、Nginx 是子进程 accept。

【流程】

1. 父进程中 mainReactor 对象通过 select 监控连接建立事件,收到事件后通过 Acceptor 接收,将新的连接分配给某个子进程。

2. 子进程的 subReactor 将 mainReactor 分配的连接加入连接队列进行监听,并创建一个 Handler 用于处理连接的各种事件。

3. 当有新的事件发生时,subReactor 会调用连接对应的 Handler(即第2步中创建的 Handler)来进行响应。

4. Handler 完成 read → 业务处理 → send 的完整业务流程。

通信协议

1. 成熟框架,通过 IDL 支持多语言;2. 性能好,底层使用 HTTP/2;

3. 基于 Protocol Buffer,性能好,可扩展;4. 实现要复杂一些。

1. 实现简单;2. 可扩展;3. 性能不如 gRPC。

1. 实现简单;2. 可扩展;3. 支持异构系统,无需嵌入 SDK;4. 性能不如 gRPC 和 TLV。

代码案例

//build netty server.BventLoopGroup bossGroup = new NioEventLoopGroup( nThreads: 1);EventLoopGroup workerGroup - new NloEventLoopGroup( nThreads: 8);try{ServerBootstrap b= new ServerBcotstrap();b.cption(Channeloption.S0_BACKLOG, value: 1024);b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new QueueServerInitlalizer(role));Channel ch = b.bind(port).sync().channel();ch.closeFuture ().sync();Finally {bossGroup.shutdounGracefully();workerGroup,shutdornGracefullyl;}

public class QueueserverInitializer extends ChannelInitializer<SocketChannel>(private final Role role;public QueueServerInitializer(Role role)( this.role = role;)@Overrideprotected void initChannel(SacketChannel socketChannel) throve Bxception AChanne lPipeline p  =  socketChannel.pipeline();P.addLast (new QueueServerDecoder (TLVData.AAXRRAME_LEWGPB,TIWData,LEWGTH FIBAD_ETINData,LENGTH FIBAD_OFFSBY,TIWData,EENGTH_ADUSTMEWT,TLWData,INITTAL_B)P.eaddLast (new QueueServerEncoder);P.addlast [new QueueServerlandler(rolel);

基于 ZooKeeper 主备切换方案

1. 设计 Path

分片之间互相独立,每个分片只有2个角色:master 和 slave,因此分片目录设计为:/com/arch/queue/{systemName}/{groupName}。

2. 选择节点类型

当 master 节点挂掉的时候,原来的 slave 要激活,接收client的读消息请求,因此用 ephemeral 类型的 znode。

3. 设计节点数据

由于数据只从 MySQL 主机复制到 MySQL 备机,因此不需要解决冲突问题,无需写入节点数据。

4. 设计 Watch

master 节点只会创建 master znode,slave 只会创建 slave znode,且 master 无需关注 slave 状态,slave 需要 watch master状态。

标签: #nettynginx游戏框架