Magician 1.1.6 发布,采用事件组管理机制

2021-05-02 13:25:36 +08:00
 Joker123456789

Magician 1.1.6,作为第一个正式的版本,内部对 NIO 的实现部分做了大量优化与重构,采用了事件组管理机制,具体模型如下图所示:

采用了两个事件组来进行事件和线程池的管理,一个叫 ioEventGroup,一个叫 workerEventGroup,都是通过 EventGroup 类创建。 每个 EventGroup 都对应一个 EventRunner,每个 EventRunner 对应一个任务队列,可以管理多个事件。 当队列空了以后,可以去其他的 EventRunner 窃取任务,不会造成资源浪费。

ioEventGroup 是用来管理 Selector 的,一个端口对应一个 EventRunner 里的一个事件,也就是说如果要监听多个端口就需要在 ioEventGroup 初始化多个 EventRunner,这么做是因为 EventRunner 是按顺序消费事件的,如果多个监听事件都给一个 EventRunner 管理,可能会执行不到后面的事件,因为 Selector 是一个死循环 他会一直占用当前线程。

workerEventGroup 是用来管理 业务事件的,一个连接对应一个 EventRunner,一个 EventRunner 对应多个连接,当连接里有了 read 事件就会往 EventRunner 里添加一个事件,EventRunner 会按顺序消费这些事件,在消费时 如果发现协议报文不完整会立刻停止该事件 继续执行下一个,如果报文完整会调用 handler 执行业务逻辑。 建议按照 CPU 的核心数来合理的设置 workerEventGroup 里的 EventRunner 数量。

具体如何使用

一、创建 TCP 服务(默认使用 http 解码器)

创建 Handler

public class DemoHandler implements MagicianHandler<MagicianRequest> {

    @Override
    public void request(MagicianRequest magicianRequest) {
        // 响应数据
        magicianRequest.getResponse()
                .sendJson(200, "{'status':'ok'}");
    }
}

创建服务(默认线程池配置)

Magician.createTCPServer()
                    .httpHandler("/", new DemoHandler())
                    .bind(8080);

创建服务(自定义线程池配置)

EventGroup ioEventGroup = new EventGroup(1, Executors.newCachedThreadPool());
EventGroup workerEventGroup = new EventGroup(10, Executors.newCachedThreadPool());

// 当前 EventRunner 没任务的时候,允许从其他 EventRunner 窃取任务
workerEventGroup.setSteal(EventEnum.STEAL.YES);

Magician.createTCPServer(ioEventGroup, workerEventGroup)
                    .httpHandler("/", new DemoHandler())
                    .bind(8080);

创建服务(监听多端口)

// 监听几个端口,ioEventGroup 的第一个参数就写几
EventGroup ioEventGroup = new EventGroup(2, Executors.newCachedThreadPool());
EventGroup workerEventGroup = new EventGroup(10, Executors.newCachedThreadPool());

// 当前 EventRunner 没任务的时候,允许从其他 EventRunner 窃取任务
workerEventGroup.setSteal(EventEnum.STEAL.YES);

TCPServer tcpServer = Magician
                         .createTCPServer(ioEventGroup, workerEventGroup)
                         .httpHandler("/", new DemoHandler())

tcpServer.bind(8080);
tcpServer.bind(8088);

二、创建 WebSocket

只需要在创建 http 服务的时候加一个 handler 即可

Magician.createTCPServer()
                    .httpHandler("/", new DemoHandler())
                    .webSocketHandler("/websocket", new DemoSocketHandler())
                    .bind(8080);

三、创建 UDP 服务

Magician.createTCPServer()
                    .httpHandler("/", new DemoHandler())
                    .webSocketHandler("/websocket", new DemoSocketHandler())
                    .bind(8080);

除了这种写法,也可以单独创建 handler,在这里 add 进去

官网:http://magician-io.com

感谢

最后需要感谢一下 曾经指出我项目中的 不足与错误点的人。因为你们我才能逐渐走上一个正确的方向,目前的版本虽然也不是很完美,性能,设计上 肯定还有很多可以优化的地方,但是已经不存在之前那个空转的低级错误了, IO 和上层协议也已经分开了,报文解码器也可自定义了。

为了不打扰到你们,所以我选择 不艾特 了。

1046 次点击
所在节点    分享创造
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/774620

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX