背景 我们一直在尝试让服务器端摆脱Pomelo
这个老框架, 让他能更符合现在主流的后端架构.在我们的概念中, 除了服务器端主动推送的通知
外,别的业务都可以通过使用无状态的http
来进行交互但受限于Pomelo
的框架,我们的全部业务都是通过长连接来实现的, 这就导致我们的业务是有状态的. 下面就是对 Pomelo
是否能支持HTTP
协议的一次调研和尝试
回顾
让我们在回顾下 现在服务端的架构吧
目标
- 不加新类型实现
HTTP
服务 - 新的
HTTP
服务支持负载均衡(无状态) - 尽量少或是不改动现有代码的基础上实现
过程
实现目标1
这个目标还是很简单,无非就是让一些进程在现有TCP监听的基础上加上HTTP端口的监听即可,最合适加HTTP端口监听的服务器类型自然是Logic进程,因为我们大部分业务都在Logic上,于是开始在Logic进程上再监听一个HTTP端口
修改配置, 为每一个Logic添加一个http端口
在启动logic进程时, 添加一个HTTP组件, 启动一个HTTP服务这样Logic进程不止支持TCP还支持HTTP了
实现目标2
打眼一看目标2也很简单, 现在每一个Logic进程都有HTTP端口了,我们在Nginx上配置下请求的端口即可实现简单的负载均衡
但目标二还有一层含义, Logic进程应该是无状态的, 怎么实现无状态的,放到目标三来说明
实现目标3
第三个目标是想在尽量不改动现有代码的基础上来实现这套逻辑, 我们先来看看现在的一个协议是如何被调用的以SPIN协议为例,最终Pomelo
会路由到下面的这段代码来 如果我们想手动执行这个方法的话,需要构建所需的参数这里有三个参数, app: 是pomelo对象, session: backend Session, next: 执行完成后的回调函数第一 三 两个参数都挺简单的, 能很简单的获取和构造得到我们看下pomelo的源代码第二个参数就挺麻烦了, 这个
backend Session
是从哪来的呢?
Backend Session从哪来的?
通过名称:找到了两个相关的文件,一个是组件,另外一个是服务, 我们主要来看服务这个文件,也就是
backendSessionService.js
我们发现这里有一个crete方法, 我找下是什么时候创建的这个backend Session吧
我又查阅了相关的文档
通过代码的注释和文档得知 每一个请求都会创建一个新的backend session, 而这个backend Session又是通过前端服务器的session创建的, 那么我们要自己去创建这个backend session的话就要获得session才行
如何获得Session
Session又是从哪来的呢?通过前文的构建图可以看出Session其实是分散到每一个connector
进程上的,我们的logic想直接获得别的进程上的信息还是比较困难的. 这时候很容易想到了第三方的存储介质, 比如我们的Redis. 可以把Session存一份到Redis吗?
登录完成后首次存储Redis
第一个想到可以存储的地方当然是登录完成后了具体实现如下:
在connector进程启动时, 加载一个叫 SessionRedisStore的组件
这个组件提供一些列操作Session的方法, 例如将Session存储到Redis中去或是从Redis中取Session信息等
当玩家登录成功后就可以手动的存储一份到redis中C2SLogin.js
同步Session信息到Redis
除了登录完成后存储的初始Session的信息, 我们还需要当Session信息改变的时候也需要同步信息到Reis中去,我们通过文档得知 当我们需要对Session信息做出修改时会调用
Push
方法(文档上没提到的还有一个PushAll
函数可以批量的修改Session里的字段)这时候我们需要做一个请求的拦截, 当调用push
的顺便去更新我们的redis
中的数据这时候Pomelo
的Filter
就派上用场了
这是文档上对Filter下的定义:我们利用Filter的原理,在执行
这个请求前,将session做一个封装,当执行session.push的时候触发我们的redis数据更新
我们在Logic启动时增加一个过滤器
这个过滤器主要是修改了push和pushAll两个函数, 在执行原push方法的同时添加了更新redis的逻辑
好了通过这一系列的修改后,我们终于实现了将session信息存储到redis中,并且可以同步session的变化了
如何自己创建Backend Session
我们上一步把session存储到了redis中,目的就是为了实现通过session创建Backend Session, 具体如何实现呢?
这里直接调用的是pomelo自己的创建方法
串联整体的逻辑
让我们重新来串联下业务逻辑
- 玩家登录到Connector进程上,将Session信息同步到Redis
- 玩家访问Logic有两种方式
- TCP: 和之前的相同
- HTTP: 通过URL路由后构建backend session最后执行C2SSpin这样我们就实现了,最少修改成本实现了HTTP协议的支持
结果展示
TCP访问
下面是一个服务器端实现的客户端程序登录:
SPIN的返回值
HTTP访问
EnterRoom
Spin
Cursor
LLM: claude-3.5-sonnet以及claude-3.7-sonnet这些代码绝大部分都是Cursor帮我实现的, 我是一步一步的提供给他思路
下面是我一个三段式的提示词,其中也用到了Cursor的 Docs和 Web功能
背景:我这个项目通过pomelo实现的, 主要有两类服务器 第一类是:connector是用于登录并和客户端保持连接的, 进程中存储了session信息, 第二类是: logic进程是用于逻辑处理的,进程中存储了另外一个session名称叫backendSession,是每次请求时connector通过session创建而来的, 这两类服务器的交互方式是 玩家在connector进程登录后,通过路由的方式转发到logic进程进行一些逻辑处理,我已经在现在的代码的基础上在logic进程上实现一个http的服务,我想实现的是玩家登录后就可以通过http请求直接访问logic服务了,实现几乎不修改代码就能支持websocket协议和http协议
需求: 现在有一个问题, 在执行时需要一个backendSession参数, 而这个backendSession就如前文说的一样,是通过connector生成的, 为了让http服务也能获得这个session, 所以我想把connector的session存一份到redis上, 并且有更新的时候能及时更新,并且提供给我通过session创建backendSession的方法
要求:参考pomelo的文档 @Pomelo中文文档 和 源代码@github.com/NetEase/pom... 来实现