
Mastra mastra/dynamodb DynamoDB 单表设计方案落地pk/sk 主键与 GSI1/GSI2 索引结构、CDK/CloudFormation 建表、TTL 配置与本地开发【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastraMastra 的mastra/dynamodb存储包采用「单表设计 ElectroDB」模式把 memory、workflows、scores、background tasks 等多个领域的数据全部写入同一张 DynamoDB 表。本文基于仓库中的 TABLE_SETUP.md 展开系统讲清建表所需的键结构pk/skgsi1/gsi2两组全局二级索引、各实体对索引的占用方式、CloudFormation 与 AWS CDK 两种建表模板、TTLTime To Live的启用与按实体配置方法以及如何把这张表接入DynamoDBStore并在本地用 DynamoDB Local 调试。读完后你可以独立完成生产环境的建表、验证表结构是否满足所有索引查询需求并正确配置自动数据过期。单表设计与表结构要求mastra/dynamodb使用单表设计single-table design模式底层通过 ElectroDB 管理实体与索引映射见 ElectroDB 服务定义。你只需创建一张DynamoDB 表结构如下表名可任意命名但必须传给DynamoDBStore构造函数的config.tableName分区键Partition KeypkString排序键Sort KeyskString全局二级索引GSIGSI1分区键gsi1pkString排序键gsi1skStringGSI2分区键gsi2pkString排序键gsi2skString。GSI 的意义在于允许在主键之外的属性上进行高效查询从而支撑 Mastra 各组件所需的不同数据访问模式。所有实体共享这一张表靠pk/sk的组合composite字段区分实体类型与主键靠gsi1pk/gsi1sk、gsi2pk/gsi2sk承载二级查询。GSI 使用明细结合源码核实原始文档给出了索引与实体的对应关系这里结合仓库中的实体定义逐一核实均位于stores/dynamodb/src/entities/目录GSI1索引名gsi1被多个实体的常见查询模式复用实体索引名查询语义源码中的组合键定义threadEntitybyResource按resourceId查询gsi1pk [entity, resourceId]gsi1sk [createdAt]见 thread.tsmessageEntitybyThread按threadId查询gsi1pk [entity, threadId]gsi1sk [createdAt]见 message.tstraceEntitybyName按name查询gsi1pk [entity, name]gsi1sk [startTime]见 trace.tsevalEntitybyAgent按agent_name查询gsi1pk [entity, agent_name]gsi1sk [created_at]见 eval.tsGSI2索引名gsi2用于实体索引名查询语义源码中的组合键定义traceEntitybyScope按scope查询gsi2pk [entity, scope]gsi2sk [startTime]见 trace.tsworkflowSnapshotEntitygsi2按run_id查询gsi2pk [entity, run_id]gsi2sk [workflow_name]见 workflow-snapshot.ts从源码结构看所有实体的pk组合都包含entity字段前缀例如 thread 的主键为pk [entity, id]即pk值形如thread#idElectroDB 借此在同一张表内实现实体隔离而gsi1pk/gsi2pk同样以[entity, ...]组合保证各实体共用 GSI 时互不冲突。仓库中共注册了 8 个实体thread、message、eval、trace、workflow_snapshot、resource、score、background_task见 entities/index.ts它们全部落在这一张表里。CloudFormation 模板下面是文档给出的完整 CloudFormation 模板反映了上述 GSI 使用方式可直接用于 IaC 流水线Resources: MastraSingleTable: Type: AWS::DynamoDB::Table Properties: TableName: mastra-single-table BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: pk AttributeType: S - AttributeName: sk AttributeType: S - AttributeName: gsi1pk AttributeType: S - AttributeName: gsi1sk AttributeType: S - AttributeName: gsi2pk AttributeType: S - AttributeName: gsi2sk AttributeType: S KeySchema: - AttributeName: pk KeyType: HASH - AttributeName: sk KeyType: RANGE GlobalSecondaryIndexes: - IndexName: gsi1 KeySchema: - AttributeName: gsi1pk KeyType: HASH - AttributeName: gsi1sk KeyType: RANGE Projection: ProjectionType: ALL # Suitable for varied query needs of GSI1 - IndexName: gsi2 KeySchema: - AttributeName: gsi2pk KeyType: HASH - AttributeName: gsi2sk KeyType: RANGE Projection: ProjectionType: ALL PointInTimeRecoverySpecification: PointInTimeRecoveryEnabled: true SSESpecification: SSEEnabled: true要点AttributeDefinitions必须完整声明主键与两个 GSI 的全部 6 个键属性否则模板部署会失败两个 GSI 均使用ProjectionType: ALL因为各实体在 GSI1 上的查询字段各不相同createdAt、startTime、created_at投影必须覆盖全部属性。AWS CDK 示例同样的结构用 AWS CDK 表达如下完整继承自文档import * as cdk from aws-cdk-lib; import { Construct } from constructs; import * as dynamodb from aws-cdk-lib/aws-dynamodb; export class MastraDynamoDbStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Consider parameterizing the table name for different environments const tableName mastra-single-table; // Create the single table const table new dynamodb.Table(this, MastraSingleTable, { tableName: tableName, partitionKey: { name: pk, type: dynamodb.AttributeType.STRING }, sortKey: { name: sk, type: dynamodb.AttributeType.STRING }, billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, pointInTimeRecovery: true, encryption: dynamodb.TableEncryption.AWS_MANAGED, }); // Add GSI1 table.addGlobalSecondaryIndex({ indexName: gsi1, partitionKey: { name: gsi1pk, type: dynamodb.AttributeType.STRING }, sortKey: { name: gsi1sk, type: dynamodb.AttributeType.STRING }, // projectionType defaults to ALL in CDK, which is suitable for flexible querying but has cost implications. }); // Add GSI2 (Used by Trace and WorkflowSnapshot) table.addGlobalSecondaryIndex({ indexName: gsi2, partitionKey: { name: gsi2pk, type: dynamodb.AttributeType.STRING }, sortKey: { name: gsi2sk, type: dynamodb.AttributeType.STRING }, // projectionType defaults to ALL in CDK }); } }注意索引名必须严格为gsi1、gsi2——源码中 ElectroDB 实体声明的index: gsi1/index: gsi2直接引用这两个物理索引名改名会导致查询失败。建表之外init() 的表校验机制与配置约束原始文档强调「表必须已通过 CDK/CloudFormation 创建」这一点在源码中可以得到印证。DynamoDBStore的init()不会自动建表而是通过DescribeTableCommand校验表存在且可访问见 storage/index.ts 中的validateTableExists表不存在时抛出Table name does not exist or is not accessible. Ensure its created via CDK/CloudFormation before using this store.权限等其他错误会被包装为MastraError错误域STORAGE向上抛出初始化结果以 Promise 缓存hasInitialized失败时重置以便重试。此外构造函数对config.tableName有硬性校验见 storage/index.ts必须提供且非空字符串必须匹配/^[a-zA-Z0-9_.-]{3,255}$/3–255 个字母、数字、下划线、点或连字符不符合会直接抛出MastraError。从源码结构看DynamoDBStoreConfigstorage/index.ts还支持以下字段官方文档示例未全部展开regionAWS 区域未指定时客户端默认us-east-1endpoint自定义端点本地开发指向 DynamoDB Local 时使用credentials显式传入accessKeyId/secretAccessKeyclient直接传入预先配置好的DynamoDBDocumentClient例如自定义中间件、重试策略disableInit设为true时禁用自动初始化适合 CI/CD 中显式执行迁移、分离部署期与运行期凭据的场景ttl按实体配置 TTL详见下文。这些字段决定了同一份表结构可以在不同环境生产 AWS、CI、本地容器中复用无需改动表本身。启用 TTLTime To Livemastra/dynamodb支持按实体类型配置 TTL实现数据的自动过期删除。前提是先在表层面启用 TTL。表级开启CloudFormation在表定义中添加Resources: MastraSingleTable: Type: AWS::DynamoDB::Table Properties: # ... other properties ... TimeToLiveSpecification: AttributeName: ttl # Must match config.ttl.[entity].attributeName (default: ttl) Enabled: trueAWS CDK建表时开启const table new dynamodb.Table(this, MastraSingleTable, { // ... other properties ... timeToLiveAttribute: ttl, // Must match config.ttl.[entity].attributeName (default: ttl) });AWS CLI对已有表开启aws dynamodb update-time-to-live \ --table-name mastra-single-table \ --time-to-live-specification Enabledtrue, AttributeNamettl三处AttributeName/timeToLiveAttribute必须与代码中config.ttl.[entity].attributeName一致默认值为ttl。代码中配置 TTL表级开启后在DynamoDBStore配置中按实体类型声明 TTL完整继承自文档示例const storage new DynamoDBStore({ name: dynamodb, config: { tableName: mastra-single-table, region: us-east-1, ttl: { message: { enabled: true, defaultTtlSeconds: 30 * 24 * 60 * 60, // 30 days }, trace: { enabled: true, defaultTtlSeconds: 7 * 24 * 60 * 60, // 7 days }, }, }, });每个实体条目支持三个字段见 storage/index.ts 的DynamoDBEntityTtlConfig类型定义enabled: boolean该实体是否启用 TTLattributeName?: stringTTL 属性名默认ttl必须与表级配置的属性名一致defaultTtlSeconds?: number自条目创建/更新起的过期时长秒例如30 * 24 * 60 * 60表示 30 天。从源码看可配置 TTL 的实体类型为thread、message、trace、eval、workflow_snapshot、resource、score七种DynamoDBTtlEntityName见 storage/index.ts。TTL 的实现细节TTL 属性写入逻辑集中在 storage/ttl.ts可以对照源码理解其行为calculateTtl()计算过期时间戳Math.floor(Date.now() / 1000) ttlSeconds即「当前时间的 epoch 秒 过期时长」——DynamoDB 的 TTL 值是 Unix 时间戳秒不是毫秒若某实体未配置enabled: true、或defaultTtlSeconds未提供/非正数则不写入 TTL 属性该条目永不过期getTtlProps()返回形如{ [attributeName]: ttlValue }的对象由各实体写入记录时展开spread进去支持在调用侧传入customTtlSeconds覆盖默认时长customTtlSeconds ?? entityConfig.defaultTtlSeconds。注意与文档一致DynamoDB TTL 是在条目过期后48 小时内由后台进程删除在真正被删除前过期条目仍然可以被查询到。使用这张表接入 DynamoDBStore表创建完成后将其接入 Mastra 应用完整继承自文档示例import { Memory } from mastra/memory; import { DynamoDBStore } from mastra/dynamodb; import { PineconeVector } from mastra/pinecone; const storage new DynamoDBStore({ name: dynamodb, config: { region: us-east-1, tableName: mastra-single-table, // use the name you chose when creating the table }, }); const vector new PineconeVector({ id: dynamodb-pinecone, apiKey: process.env.PINECONE_API_KEY, }); const memory new Memory({ storage, vector, options: { lastMessages: 10, semanticRecall: true, }, });从源码看DynamoDBStore继承自MastraCompositeStore内部一次性组装了四个领域存储workflows、memory、scores、backgroundTasks见 storage/index.ts。因此这一张表同时承担会话/消息持久化memory、工作流快照持久化workflowSnapshotEntity走 GSI2 的run_id查询、评估数据与后台任务存储无需为每个组件单独建表。所有领域共享同一个由getElectroDbService(client, tableName)创建的 ElectroDBService实例entities/index.ts。本地开发DynamoDB Local文档建议本地开发直接使用 AWS 官方的 DynamoDB Local Docker 镜像docker run -p 8000:8000 amazon/dynamodb-local然后把DynamoDBStore的endpoint指向本地实例const storage new DynamoDBStore({ name: dynamodb, config: { region: us-east-1, tableName: mastra-single-table, endpoint: http://localhost:8000, // Local DynamoDB endpoint }, });region在本地模式下只是占位参数本地端点不校验区域。仓库内还附带了 stores/dynamodb/docker-compose.yml可以直接用它拉起本地 DynamoDB 环境效果与上述docker run命令等价。注意本地库与线上一样需要先建好pk/sk/gsi1/gsi2结构的表init()的DescribeTableCommand校验才会通过。小结建表核对清单对照本文内容与源码落地这张表时可按以下清单核对表包含pkHASHskRANGE主键以及gsi1gsi1pk/gsi1sk和gsi2gsi2pk/gsi2sk两个 GSI且 GSI 索引名必须为gsi1、gsi2AttributeDefinitions完整声明 6 个键属性config.tableName与建表名一致且满足 3–255 字符、仅含字母/数字/_/./-的校验规则若启用 TTL表级 TTL 属性名与config.ttl.[entity].attributeName一致默认ttl并对message、trace等需要过期的实体配置enabled与defaultTtlSeconds本地调试时使用endpoint: http://localhost:8000指向 DynamoDB Local或参考仓库附带的 docker-compose.yml。以上结构即 TABLE_SETUP.md 所定义的全部要求与stores/dynamodb/src/entities/下各实体的索引声明一一对应可直接用于生产环境的 IaC 部署与本地开发。【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考