浅谈微服务及其在游戏里的应用
一般来说,微服务(Microservices)的概念被认为最早是2011年在威尼斯的一场会议上面讨论并提出的最初只是一些通用的设计原则和系统架构。在随后的几年内,随着诸如Fred George和Martin Fowler等人的演讲和文章的出现,微服务架构逐渐开始流行,越来越多的公司和项目开始借鉴和使用微服务架构相关的技术。时至今日,虽然微服务架构并没有一个官方的定义,但是相比于传统的SOA(Service-oriented architecture)架构,微服务有以下几个典型的特点:
- 细颗粒度的服务划分
- 每个服务可以单独部署
- 服务之间使用语言无关的协议通讯,如http,tcp等
这也意味着在一个微服务的系统里面,可能你用的数据库操作是用java写的,http服务是用node.js写的,一些具体的业务服务又是用python写的。没有任何强制的规定用哪种语言来实现,换句话说就是什么最合适就用什么。
微服务架构的演变
微服务本身的架构也不是一成不变的,Phil Calçado有一篇文章《Pattern: Service Mesh》非常详细的介绍了从微服务诞生前到现在的系统架构演变历史。大概可以总结为几个阶段:
1 | 数据传输逻辑和业务逻辑写在一起 |
可以看到总的发展趋势其实一直就是在朝一个方向发展,即业务逻辑和底层架构分开。服务网格(Service Mesh,一种较新的微服务架构)这个词的发明者William Morgan说过这么一段话:
“A service mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. In practice, the service mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code, without the application needing to be aware”
从infrastructure layer这一词可以看出,Service Mesh在现代的分布式架构的系统中充当的角色和TCP/IP协议在传统网络环境中扮演的角色很像,一个解决的end to end之间通信的可靠性问题,一个是屏蔽了分布式系统带来的复杂性问题,总之都是实现了一种对应用层透明的基础传输设施。
微服务在游戏中应用
通常来说,比较适合做成微服务的业务逻辑都是无状态的,而绝大部分游戏却又都是典型的强状态业务。但是随着游戏用户的日益增加,游戏服务器的规模也日益庞大。尤其是一些喜欢做成开放大世界的游戏,其游戏服务器本身就是一个复杂的分布式系统。在这种情况下,把游戏中一些可以抽象出来的无状态业务从核心模块里面剥离出来做成微服务,既能够减少承载核心业务机器的负载,又可以减少非核心业务发生故障对玩家游戏体验的影响。通常来说,一些可以抽出来做微服务的有诸如邮件系统,好友系统,匹配系统,聊天系统等,而一些和玩家状态强相关的比如属性,战斗之类的则没有办法。一个比较简单的衡量业务是否适合做成微服务的标准就是:这个微服务是否可以随时重启,重启带来的影响越小则越适合。
接下来我们以游戏中的聊天系统为例子,来分析一下在游戏中引入微服务的优缺点。今天,大部分游戏的聊天功能的需求早已不仅仅是满足与一局游戏内部的聊天而已了,一张地图/一个服务器内的聊天,玩家与玩家之间的私聊,群聊,离线消息,全服广播,乃至不同种类设备之间的聊天(比如使用手机助手的玩家和游戏内的玩家之间的聊天)等等需求。与其说这是一个游戏内的功能,不如说这是一个简易版本的IM应用了。而从实现角度来看,聊天系统是可以完全和游戏玩法解耦开的,其本身又是一个弱状态的业务,因此,使用微服务来实现是完全可行的。
进一步分析,对于服务调用方,通常一个聊天系统只需要实现发送,拉取,订阅,推送四个基本的功能就可以满足绝大部分业务需求。而对于微服务自己内部,一个现有的非常成熟的技术可以非常轻松的实现这些需求,那就是消息队列。把一个聊天的业务抽象起来看就是某个客户端往某个指定的频道发送了一些消息,而这个频道可能有两个订阅者(私聊)或者很多个订阅者(群聊),而这些订阅者有一个统一的目的,就是在有人往这个频道发送消息的时候能够尽快得到通知。一般在消息队列中,我们称之为“发布–订阅”模型。一方面微服务上可以根据聊天的类型,生成不同的频道号来区分客户端发送过来的消息类型从而转发到消息队列不同的话题里。另一方面,当消息队列某个话题有新内容推送过来时,微服务这里只需要解析一下这个话题,然后向关注这个话题的客户端推送这些消息。
与直接嵌入在游戏服务器内部的聊天系统实现相比,这种使用微服务的实有几个显而易见的优势:
- 1.扩展性,聊天系统的负载较高时,单独对微服务进行扩容就可以了,无需操作游戏服务器
- 2.独立性,没有和游戏服务器的耦合关系,可以单独开发,单独升级,如果线上出现问题,还可以及时熔断进行降级,防止“雪崩”效应
- 3.可靠性,不再受限于游戏服务器内部实现的限制,可以尽情使用最新的技术架构来保证稳定可靠
与之对应的,引入微服务也带来了一些额外的开销:
- 1.额外的复杂性,虽然我们上面分析的时候非常简单,但是实际实践下来还是有很多坑的存在,尤其是在引入了第三方的消息队列以后
- 2.额外的性能开销,与做在游戏服内部的实现相比,消息链路有了明显的加长,序列化/反序列化,网络通信都是额外的开销
- 3.额外的运维监控,本身已经是一个需要监控的独立的业务系统(当然,前提是你确实需要一个这样强大的业务系统)
不要为了微服务而微服务
前面吹了这么多微服务的好处,可能大部分人都会认为此篇文章是来鼓吹和推广微服务的。但是,我的本意恰恰相反,我强烈不建议盲目引入微服务到现有的架构中。是否需要引入微服务绝对是一个要多方权衡的东西,且不说微服务本身通常会带来的额外延时开销,开发团队的能力、企业的组织结构、业务本身的特点等等都是需要纳入考虑的点。所幸的是网络游戏发展到今天,已经演化很多通用的基础功能,比如聊天,好友,邮件,匹配等等。以现在的中大型网络游戏的用户规模而言,这些系统还是非常适合做成微服务的。但即使如此,在开发的前期,在业务逻辑和系统边界还不是那么清晰的时候,还是要谨慎考虑,千万不要陷入拿着解决方案找问题的“陷阱”之中。