DynamoDB存储IAM用户数据的最优结构及查询方案咨询
IAM用户数据DynamoDB存储方案优化
当前设计的核心问题
你的初始设计仅围绕账号维度做了聚合,存在三个关键缺陷:
- 用户与访问密钥无直接关联:无法通过用户快速找到其所有密钥,也没法通过密钥直接定位所属用户
lastUsed时间范围查询无高效路径:仅靠主表无法快速筛选指定日期后使用过的密钥,单独建GSI又容易造成资源浪费- 实体关联逻辑缺失:密钥项未冗余用户信息,跨实体查询需要额外遍历,效率低下
优化后的主表与GSI设计
采用多态主键+定向GSI的组合方案,兼顾所有查询场景,同时遵循DynamoDB"空间换时间"的设计原则:
主表结构
| 实体类型 | PK | SK | 核心属性 |
|---|---|---|---|
| IAM用户 | ACCOUNT#<account_id> | USER#<user_name> | 用户ID、创建时间、状态等 |
| 访问密钥 | ACCOUNT#<account_id> | ACCESSKEY#<access_key_id> | 密钥ID、所属用户名user_name、最后使用时间last_used、状态等 |
全局二级索引(GSI)配置
GSI1:用户-密钥关联索引
- 分区键(GSI1PK):
USER#<user_name> - 排序键(GSI1SK):
ACCESSKEY#<access_key_id> - 投影属性:
account_id、last_used、status
- 分区键(GSI1PK):
GSI2:密钥-用户反向索引
- 分区键(GSI2PK):
ACCESSKEY#<access_key_id> - 排序键(GSI2SK):
USER#<user_name> - 投影属性:
account_id、last_used
- 分区键(GSI2PK):
GSI3:密钥使用时间索引
- 分区键(GSI3PK):
KEY_LAST_USED(固定值,用于聚合所有密钥的使用时间) - 排序键(GSI3SK):
last_used(建议用ISO8601格式字符串,如2024-05-20T12:34:56Z) - 投影属性:
access_key_id、user_name、account_id
- 分区键(GSI3PK):
各查询场景的高效实现
查询某账号下所有密钥与用户信息
- 主表查询:指定PK=
ACCOUNT#<account_id>,无SK过滤条件,直接扫描该分区下所有项
- 主表查询:指定PK=
查询某账号下所有用户信息
- 主表查询:PK=
ACCOUNT#<account_id>,SK条件设为BEGINS_WITH('USER#')
- 主表查询:PK=
查询某账号下所有访问密钥信息
- 主表查询:PK=
ACCOUNT#<account_id>,SK条件设为BEGINS_WITH('ACCESSKEY#')
- 主表查询:PK=
查询所有指定日期后使用过的密钥
- GSI3查询:指定GSI3PK=
KEY_LAST_USED,SK条件设为>= '<目标日期ISO字符串>',直接获取所有符合时间范围的密钥
- GSI3查询:指定GSI3PK=
查询特定访问密钥所属用户
- GSI2查询:指定GSI2PK=
ACCESSKEY#<access_key_id>,返回结果中直接包含所属用户名和账号ID
- GSI2查询:指定GSI2PK=
查询特定用户的所有访问密钥
- GSI1查询:指定GSI1PK=
USER#<user_name>,返回该用户关联的所有密钥项
- GSI1查询:指定GSI1PK=
额外优化点
- 属性冗余:在密钥项中冗余存储
user_name和account_id,避免跨索引/表查询,虽然增加少量存储,但大幅提升查询效率 - 时间戳规范:统一使用ISO8601格式存储
last_used,既保证排序正确性,也便于人工排查 - GSI投影策略:仅投影必要属性,减少GSI的存储和写入开销,比如GSI3无需存储密钥的完整状态信息
内容的提问来源于stack exchange,提问作者DenCowboy
相关产品推荐
相关产品推荐

