多人互砍游戏的后台服务器的多线程架构 -ag凯发k8国际
概述
本文叙述从最简单的单线模型程进化多线程的模型。不用 spring 而是用普通的 java 代码,只做了登录、移动、互砍、伤害计算,英雄死亡等功能的最最简单的版本,主要讨论的是框架架构,不是业务有多绚。
1.服务器处理客户端的连接和客户端指令当然用 netty。
2.客户端用 cocos,本文不讨论,协议自定义好了,生成 java 代码用protobuf,本文不讨论。
3.用到的设计模式,工厂 策略、单例、观察者。
为什么游戏服务器用单线程
一般会认为单线程处理超高并发的应用时慢,其实绝大部分应用的性能瓶颈是 io 和 fullgc。 比如网游一般是同步模型的,分区分服务器的架构,即使需要多个服务器之间共享数据,也是由另外的服务器去处理,对客户端是不可见的。
1.游戏服务器的协议是自定义的(对比web服务器用的是http协议,网络传输直接传的字符串,游戏服务器传很小的字节数组)请求的包很小,网络io没问题。
2.游戏服务器是长连接(对比web服务器,session保持几分钟的不同),连接建立了就不释放,然后就一直玩,砍。基本上是客户端退出了才断开连接。
3.单线程能保证数据的一致性。比如,多个人互砍,每个人的砍的动作的指令在服务器里是 netty 的不同 eventloop 的线程处理的,那伤害在这么多个线程里同步加锁是不切实际的。
好的架构应该是足够简单,不可为了炫技搞得很复杂。在增加业务时改动足够少或者没有改动而是纯增加。
反射和 javaassist 用起来,比如 mybatis 只需要写接口没有实现类就可以直接使用,就是用的反射和 assemble(类似与javaassist的一个组件),在运行时直接生成实现类的硬编码,从而直接使用。
上代码
代码实现处理客户端连接(netty),客户端的移动、互砍指令(netty)
最普通的单线程架构
为了数据同步,把netty 的多线程处理汇总到一个单线程 mainthreadprocessor 处理。想象一种场景,多人在线的同时(移动,互砍等动作)有很多人同时在登录,而登录是要写数据库(io操作)的,那么io操作会阻塞其他在线的人的动作,砍一刀要1ms,如果io阻塞500ms,那那么多人还砍个屁啊。所以要把 io 操作和其他操作分开。
把登录操作分开到其他线程
这样,每次用户登录都用新的线程处理。这样虽然解决了io耗时问题,但是如果一个用户在操作io的线程完成之前重复登录多次呢,线程之间不通信,就会有同样业务的多条数据被写进数据库,业务错误。
把固定业务的操作放到固定的线程
这样,使用一个线程池,用某个算法(比如用户名的hash对线程池长度取模)定死了某个用户的登录在某个线程进行,就算用户再重复快速登录,线程也会阻塞等前一个任务执行完,就不会重复写了。
一般会想到线程间通信来解决此类问题,正如之前所说,线程间通信的做法不推荐。
此处只是用登录举例,但凡是io操作的,都可以一次类推。
代码太多了,不好贴出来,其实架构上还是有亮点的,比如编码和解码自动化,业务逻辑的增加自动化。观察者用java8 的函数式接口实现等等吧。想共同学习的朋友私信我。
总结
以上是ag凯发k8国际为你收集整理的多人互砍游戏的后台服务器的多线程架构的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 手撕 rpc 2
- 下一篇: zookeeper配置中心