游戏对外服缓存
本篇内容是游戏对外服相关的扩展。
本篇文档不是必读内容,但介绍了一种性能提升的技巧,建议在时间充裕时阅读。
介绍
我们对业务数据做缓存时,一般的做法是通过 Caffeine、 cache2k、 ehcache、 JetCache 等专业的缓存库,将业务数据缓存在游戏逻辑服中,以实现对业务数据的缓存。
而游戏对外服缓存,可以将一些热点的业务数据缓存在游戏对外服中。 当玩家每次访问相关路由时,会直接从游戏对外服内存中取数据。 这样既能避免反复请求游戏逻辑服,又能减少序列化(编码)业务数据,从而做到性能的超级提升。
当我们把游戏对外服缓存与专业的缓存库做结合时,可以发挥更大的性能效果。 因为我们可以将热点数据缓存在游戏对外服中,之后其他玩家访问热点数据时, 就不需要去游戏逻辑服中取数据,而是直接在游戏对外服这一环节中就能得到数据了。
游戏对外服缓存对性能有着巨大的提升,主要体现在几个方面
- 当玩家访问缓存数据时,响应更快了,因为请求链更少了。
- 直接在游戏对外服中取数据,无需将请求传递到游戏逻辑服中,无需对业务数据做序列化操作。
- 避免请求传递到游戏逻辑服中,节省系统资源。
特点
- 零学习成本
- 可快速响应玩家请求。
- 简化了缓存的使用,即使没有在游戏逻辑服中对这些业务数据做缓存, 只要在游戏对外服配置好相关的路由缓存,就能达到缓存的效果。
- 减少请求传递,同时游戏对外服缓存还可以减少请求的传递, 使得业务数据在游戏对外服就能处理,而不需要经过游戏逻辑服。
- 避免序列化操作,由于路由对应的业务数据是以 byte[] 类型缓存在游戏对外服的, 所以从缓存中取得的业务数据,将不再需要序列化(编码)操作了。 简单点说,就是不需要将业务对象转换成 byte[] 类型了。
- 支持条件缓存,同一 action 支持不同的请求参数。
- 支持路由范围缓存配置
对比各解决方案
为了让开发者更好的理解游戏对外服缓存的优势,这里先引入两个开发者常用的第三方解决方案来做对比。
与 Hazelcast、Redis 等第三方解决方案相比较
- Redis 有一些额外的开销,比如序列化和反序列化数据、对数据进行压缩和解压缩、网络IO、网络波动等方面。 使用游戏对外服缓存特性可以有效避免这些问题,并且性能是 Redis 的数百倍。
- Hazelcast 也有一些额外的开销,每个节点占用的内存几乎相同, 无论这些内存数据是否对你有用,都会强行占用你的内存。 如果其中一个节点占用了 1G 内存,那么其他节点也将占用 1G 内存。 每次数据发生变动时,都需要经过N个节点的序列化、N个节点的网络IO等操作。 对于不熟悉 Hazelcast 的开发者来说,安装、配置和调试 Hazelcast 集群可能会比较复杂,需要花费一定的时间和精力。
使用 Hazelcast、Redis 等第三方解决方案,缺点
- 第三方解决方案需要你进行额外的安装(安装成本、机器资源占用成本)。
- 在项目中引入第三方后,需要学习相关 API 的使用(学习成本)。
- 需要你进行很多额外的工作,例如数据的存储、更新等(使用成本、维护成本)。
对比小结
最重要的是,开发者使用游戏对外服缓存时,是无感知的(零学习成本)。
游戏对外服缓存 | Hazelcast | Redis | 描述 | |
---|---|---|---|---|
高性能 | ✅ | ✅ | ❌ | 两者比 Redis 快数百倍 |
零安装成本 | ✅ | ❌ | ❌ | |
零学习成本 | ✅ | ❌ | ❌ | |
零使用成本 | ✅ | ❌ | ❌ | |
零维护成本 | ✅ | ❌ | ❌ | |
内存占用 | 按需增加 | 节点均等 | 内存加载所有 | |
序列化次数 | 0 | 0 | N | 每次访问缓存时 |
网络 io 次数 | 0 | 0 | N | 每次访问缓存时 |
使用场景
使用场景举例
- 如一些配置数据信息 : 装备的配置、道具的配置... 等。
- 排行榜,如果及时性要求不高的,比如能接受 1、5、10、N 分钟同步一次的这种延迟排行榜,且数据量不多的(百来条或几百条)。
- 更多举例后续补充...
游戏对外服缓存的适用场景
- 热点数据
- 请求较为频繁的,数据不常变动的。
你可以将游戏对外服看成一台另类的 "Nginx、OpenResty" 等服务器, 可为整体架构做一些前置抵挡、功能扩展等职责。
游戏对外服缓存并不是用于取代 Hazelcast、Redis 之类的,只是在某些业务场景下会具备更大的优势。
缓存处理流程图
缓存处理流程图说明
- Player : 玩家。
- ExternalServer : 游戏对外服。
- request : 玩家发送请求。
- response : 游戏对外服的响应数据。
- cacheData : 缓存数据。检测到该请求有对应的缓存,将缓存结果发送给玩家,否则到游戏逻辑服中获取。
如何使用
游戏对外服缓存的使用与路由访问权限控制类似, 如果你之前了解过这部分的内容,那么花几分钟就能上手了。
- code 2,框架内置的缓存类
- code 3,添加全局配置中
- code 4,配置缓存 3-1
void extractedExternalCache() {
DefaultExternalCmdCache externalCmdCache = new DefaultExternalCmdCache();
ExternalGlobalConfig.externalCmdCache = externalCmdCache;
externalCmdCache.addCmd(3, 1);
}
当玩家请求 3-1 时,如果在游戏对外服中找到了缓存数据,就直接在游戏对外服环节将数据响应给玩家。
如果没有找到缓存数据,请求将被传递到游戏逻辑服,由游戏逻辑服的操作进行处理。 在操作完成后,游戏逻辑服将返回结果给游戏对外服,并将该结果保存到缓存中。 下次其他玩家请求 3-1 时,就可以从缓存中获取结果,从而实现快速响应。
更多配置
CmdCacheOption
CmdCacheOption 是游戏对外服的缓存配置对象,缓存配置对象可以让我们在游戏对外服缓存上做更精细的控制。
代码说明
- code 3,缓存过期时间 1 小时。
- code 4,缓存过期检测时间间隔 5 分钟。
- code 5, 同一个 action 的缓存数量上限设置为 256 条。
- code 6,构建缓存配置项。
CmdCacheOption createCmdCacheOption() {
return CmdCacheOption.newBuilder()
.setExpireTime(Duration.ofHours(1))
.setExpireCheckTime(Duration.ofMinutes(5))
.setCacheLimit(256)
.build();
}
即使不设置,框架默认也是这个配置,这里只是展示如何创建的缓存配置选项。
配置不同的 CmdCacheOption
- code 7,设置默认的缓存配置项,之后添加的路由缓存都将使用这个缓存配置。
- code 9,添加路由缓存 22-1,将使用默认的缓存配置。
- code 11 ~ 17,创建一个新的缓存配置对象,并设置到 22-2 、22-3 的路由中。 (不会使用默认的配置,而是使用 optionCustom 这个缓存配置对象。)
...
void extractedExternalCache() {
DefaultExternalCmdCache externalCmdCache = new DefaultExternalCmdCache();
ExternalGlobalConfig.externalCmdCache = externalCmdCache;
CmdCacheOption defaultOption = createCmdCacheOption()
externalCmdCache.setCmdCacheOption(defaultOption);
externalCmdCache.addCmd(22, 1);
CmdCacheOption optionCustom = CmdCacheOption.newBuilder()
.setExpireTime(Duration.ofSeconds(30))
.setExpireCheckTime(Duration.ofSeconds(5))
.build();
externalCmdCache.addCmd(22, 2, optionCustom);
externalCmdCache.addCmd(22, 3, optionCustom);
}
路由范围缓存配置
这里,我们添加了主路由为 2 的值,游戏对外服会对主路由为 2 下所有子路由的数据进行缓存。 通过路由范围缓存,我们可以避免为每个路由做单独的配置。
举个例子,对于 2-1、2-2、2-N 等子路由,即使你没有为这些子路由配置相关的缓存,缓存仍然会生效。 子路由使用的缓存配置与主路由使用的缓存配置相同。
void extractedExternalCache() {
DefaultExternalCmdCache externalCmdCache = ...
externalCmdCache.addCmd(2);
}
Example Source Code
see https://github.com/iohao/ioGameExamples
path : SimpleExample/example/example-external-cache
- CacheApplication
- WsClient
之后在模拟客户端的控制台中分别输入 22-1、22-2、22-3 来观察效果。