
Aspire 托管 Garnet 缓存资源从容器编排、连接注入到数据持久化的完整实战指南【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire导读Aspire.Hosting.Garnet是 Aspire 官方提供的一款托管集成hosting integration用于在 Aspire 应用模型中建模、配置并编排一个Garnet 缓存容器资源并通过WithReference把连接信息自动注入到消费方应用。本文以 Aspire.Hosting.Garnet/README.md 为主线结合其源码实现GarnetBuilderExtensions.cs、GarnetResource.cs与测试用例tests/Aspire.Hosting.Garnet.Tests系统讲解如何添加集成、在 C# 与 TypeScript AppHost 中使用、理解四个连接属性的生成规则以及如何通过数据卷、绑定挂载与快照/AOF 持久化让缓存数据在容器重启后依然保留。一、Garnet 托管集成是什么Garnet 是微软开源的高性能远程缓存存储系统兼容 RESP 协议可以作为 Redis 的替代方案接入现有生态如StackExchange.Redis客户端。在 Aspire 中Aspire.Hosting.Garnet把这个服务封装为一个一等资源first-class resource它不是一个单纯的“容器模板”而是一个实现了IResourceWithConnectionString的ContainerResource见 GarnetResource.cs这意味着资源被纳入 Aspire 应用模型可被统一编排、监控与发布通过WithReference即可自动注入连接配置集成自动注册健康检查仪表盘Dashboard中可直接观测资源状态既可用于本地开发Docker/Podman 容器也可通过 manifest 发布到 Kubernetes 等部署环境。在仓库中Aspire.Hosting.Garnet项目Aspire.Hosting.Garnet.csproj依赖Aspire.Hosting与AspNetCore.HealthChecks.Redis后者正是其健康检查能力的来源。该集成默认使用ghcr.io/microsoft/garnet:1.0容器镜像注册表、镜像名与标签常量定义在 GarnetContainerImageTags.cs 中。二、快速开始添加集成在 AppHost 项目目录下使用 Aspire CLI 添加Aspire.Hosting.Garnet集成aspire add Aspire.Hosting.Garnet命令会在 AppHost 项目中加入对应包引用之后即可在Program.csC#或apphost.mtsTypeScript中使用AddGarnet扩展方法。三、使用示例C# 与 TypeScriptC# AppHost在 AppHost 中创建 Garnet 资源并让服务通过WithReference引用它var garnet builder.AddGarnet(cache); var myService builder.AddProjectProjects.MyService() .WithReference(garnet);TypeScript AppHostAspire 的多语言polyglotAppHost 同样支持 Garnet 集成API 与 C# 一一对应const garnet await builder.addGarnet(cache); const myService await builder.addNodeApp(myService, ../my-service, server.js) .withReference(garnet);在源码层面TypeScript/Go/Python/Java 等 polyglot 宿主调用的是AddGarnetForPolyglot内部方法带[AspireExport(addGarnet)]特性见 GarnetBuilderExtensions.cs它只是对 C# 主重载的转发因此两种宿主行为完全一致。仓库中tests/PolyglotAppHosts/Aspire.Hosting.Garnet/目录下提供了 Go、Python、Java、TypeScript 四种语言的完整示例如 TypeScript/apphost.mts。四、深入源码AddGarnet到底做了什么了解 API 用法之后我们再看 GarnetBuilderExtensions.cs 中AddGarnet的完整签名public static IResourceBuilderGarnetResource AddGarnet( this IDistributedApplicationBuilder builder, [ResourceName] string name, int? port null, IResourceBuilderParameterResource? password null)调用时它会依次完成以下编排密码参数若未显式传入password参数则调用CreateDefaultPasswordParameter自动生成一个名为{name}-password的随机密码参数见 GarnetBuilderExtensions.cs。生成的密码会注入到连接字符串与GARNET_PASSWORD环境变量中。端点映射容器内部目标端口固定为6379targetPort: 6379外部端口由port参数决定不传则随机分配。测试用例 AddGarnetTests.cs 验证了端点名称为tcp、协议为tcp且默认不对外暴露。容器镜像使用ghcr.io/microsoft/garnet:1.0Registry/Image/Tag 定义于 GarnetContainerImageTags.cs。健康检查通过AddHealthChecks().AddRedis(...)注册 Redis 兼容健康检查检查项名为{name}_check并在仪表盘中展示。启动命令通过WithEntrypoint(/bin/sh)配合-c参数构造容器启动命令GarnetBuilderExtensions.cs基础命令为/app/GarnetServer --protected-mode no其中--protected-mode no用于关闭 Garnet 的保护模式允许容器外部访问源码注释明确说明了这一点配置了密码时追加--auth Password --password $GARNET_PASSWORD密码通过GARNET_PASSWORD环境变量注入之所以用环境变量而非直接内联参数源码引用了 microsoft/aspire#3838 的讨论若配置了持久化则追加--checkpointdir /data/checkpoints --recover --aof --aof-commit-freq {interval}。生成的 manifest 形态上述编排最终会序列化为容器 manifest。以下默认配置的 manifest 来自测试 AddGarnetTests.cs为便于阅读做了格式化{ type: container.v0, connectionString: {myGarnet.bindings.tcp.host}:{myGarnet.bindings.tcp.port},password{myGarnet-password.value}, image: ghcr.io/microsoft/garnet:1.0, entrypoint: /bin/sh, args: [ -c, /app/GarnetServer --protected-mode no --auth Password --password $GARNET_PASSWORD ], env: { GARNET_PASSWORD: {myGarnet-password.value} }, bindings: { tcp: { scheme: tcp, protocol: tcp, transport: tcp, targetPort: 6379 } } }这段 manifest 同时印证了本文第一节的所有要点连接字符串采用表达式在部署时解析、镜像版本、启动参数与环境变量全部由集成自动生成。五、连接属性详解当消费方通过WithReference引用 Garnet 资源后Aspire 会把以下连接属性注入给目标应用见 GarnetResource.cs 中的GetConnectionProperties实现以及 ConnectionPropertiesTests.cs 的逐项断言属性名说明HostGarnet 服务器的主机名或 IP 地址PortGarnet 服务器监听的端口号Password认证密码仅在配置了密码参数时存在Uri连接 URI格式为redis://:{Password}{Host}:{Port}Aspire 会将每个属性以环境变量的形式暴露给消费方命名规则为[RESOURCE]_[PROPERTY]资源名大写、属性名大写。例如名为cache的资源其Uri属性对应环境变量CACHE_URI同理还有CACHE_HOST、CACHE_PORT以及配置密码时的CACHE_PASSWORD。从源码可以进一步确认这些属性的底层实现Host与Port均取自名为tcp的主端点PrimaryEndpoint端点常量见 GarnetResource.cs在运行时会解析为实际的容器地址与端口UriExpressionGarnetResource.cs按redis://[:{password}]{host}:{port}拼接未配置密码时省略密码段密码使用:uri格式化器进行 URI 转义连接字符串ConnectionStringExpressionGarnetResource.cs格式为{host}:{port},password{password}这是StackExchange.Redis客户端直接可用的标准连接字符串格式。值得注意的一个细节密码默认是随机生成的未显式传入password参数时这保证了开箱即用的安全性。如果需要固定密码可以在 AppHost 中用builder.AddParameter(...)创建参数并传入var pass builder.AddParameter(pass, your-password); var garnet builder.AddGarnet(cache, password: pass);对应测试 AddGarnetTests.cs 验证了此时连接字符串会引用该参数{pass.value}。六、数据持久化数据卷、绑定挂载与快照/AOF缓存服务的容器一旦销毁内存中的数据默认也会丢失。Aspire.Hosting.Garnet为此提供了三个扩展方法全部定义于 GarnetBuilderExtensions.cs且已被导出到 polyglot 宿主1.WithDataVolume为容器添加一个名为data的命名卷挂载到容器内固定目录/data常量GarnetContainerDataDirectory见 GarnetBuilderExtensions.cs并自动启用持久化var cache builder.AddGarnet(cache) .WithDataVolume(); // 自动开启持久化签名WithDataVolume(string? name null, bool isReadOnly false)。卷名默认由应用名与资源名自动生成形如{app}-{resource}-data。若isReadOnly: true则不会启用持久化测试 AddGarnetTests.cs 验证了只读卷不会追加--checkpointdir参数。2.WithDataBindMount把宿主机上的一个目录绑定挂载到/data适合希望数据直接落在宿主机指定路径的场景var garnet builder.AddGarnet(garnet) .WithDataBindMount(mydata) // 相对 AppHost 目录解析 .WithPersistence(TimeSpan.FromSeconds(10));签名WithDataBindMount(string source, bool isReadOnly false)。source为宿主机目录测试表明相对路径会基于AppHostDirectory解析AddGarnetTests.cs。同样的isReadOnly: true时不启用持久化。3.WithPersistence显式控制持久化行为可独立于数据卷使用public static IResourceBuilderGarnetResource WithPersistence( this IResourceBuilderGarnetResource builder, TimeSpan? interval null)interval快照导出的时间间隔默认 60 秒该方法通过PersistenceAnnotation记录配置ResourceAnnotationMutationBehavior.Replace保证重复调用时旧注解被替换不会重复追加启动参数见 AddGarnetTests.cs仓库中还保留了一个带keysChangedThreshold参数的旧重载但已标记[Obsolete]新代码应使用不带该参数的重载GarnetBuilderExtensions.cs。持久化背后的启动参数开启持久化后Garnet 容器的启动命令会变为对应测试 AddGarnetTests.cs/app/GarnetServer --protected-mode no --auth Password --password $GARNET_PASSWORD --checkpointdir /data/checkpoints --recover --aof --aof-commit-freq 60000各参数含义参数作用--checkpointdir /data/checkpoints指定快照checkpoint存储目录位于数据卷/绑定挂载的/data之下--recover启动时从快照恢复数据--aof开启追加写文件Append-Only File日志--aof-commit-freq 60000AOF 提交频率单位为毫秒对应interval默认 60 秒 → 60000ms组合使用WithDataVolume()/WithDataBindMount()与WithPersistence(TimeSpan.FromSeconds(10))可以精细控制恢复粒度例如把提交频率从默认 60 秒收紧到 10 秒以降低数据丢失窗口。七、在消费方应用中使用连接配置通过环境变量读取引用 Garnet 资源后消费方应用可以直接读取注入的环境变量var host Environment.GetEnvironmentVariable(CACHE_HOST); var port Environment.GetEnvironmentVariable(CACHE_PORT); var uri Environment.GetEnvironmentVariable(CACHE_URI);配合Aspire.StackExchange.Redis客户端Garnet 兼容 RESP 协议因此可以像使用 Redis 一样使用StackExchange.Redis客户端。Garnet 集成的 XML 文档注释中给出了消费方示例见 GarnetBuilderExtensions.csvar builder WebApplication.CreateBuilder(args); builder.AddRedisClient(garnet); var multiplexer builder.Services.BuildServiceProvider() .GetRequiredServiceIConnectionMultiplexer(); var db multiplexer.GetDatabase(); db.HashSet(key, [new HashEntry(hash, value)]); var value db.HashGet(key, hash);注意此处AddRedisClient中使用的名称必须与 AppHost 中AddGarnet传入的资源名一致资源名即连接字符串名。八、从源码视角理解整体设计资源类型GarnetResource继承ContainerResource并实现IResourceWithConnectionStringGarnetResource.cs同时实现了Host、Port、UriExpression等ReferenceExpression属性——这是 Aspire 中“延迟解析连接信息”的典型模式值在运行时/部署时才被解析。API 面通过[AspireExport]特性见 api/Aspire.Hosting.Garnet.cs将addGarnet、withDataVolume、withDataBindMount、withPersistence导出到 TypeScript 等多语言宿主而两个带port参数的 C# 重载被[AspireExportIgnore]标记因为 polyglot 宿主统一走AddGarnetForPolyglot。测试覆盖tests/Aspire.Hosting.Garnet.Tests目录下的 AddGarnetTests.cs 与 ConnectionPropertiesTests.cs 对端点、镜像、manifest、连接属性与持久化参数做了逐项断言此外tests/Aspire.Cli.EndToEnd.Tests/KubernetesDeployWithGarnetTests.cs还覆盖了 Garnet 资源的 Kubernetes 部署场景tests/PolyglotAppHosts/Aspire.Hosting.Garnet/提供了 Go、Python、Java、TypeScript 的多语言宿主示例。真实示例仓库 playground 中 playground/Redis/Redis.AppHost/AppHost.cs 使用builder.AddGarnet(garnet)演示了该集成在实际示例中的用法。九、总结Aspire.Hosting.Garnet是一个“开箱即用”的托管集成一条AddGarnet调用即可完成容器镜像选择、端口映射、随机密码生成、健康检查注册与连接信息注入通过WithReference和[RESOURCE]_[PROPERTY]环境变量规范消费方无需关心部署细节借助WithDataVolume、WithDataBindMount与WithPersistence缓存数据可以基于快照与 AOF 日志在容器重启后完整恢复。无论是 C# 还是 TypeScript AppHost无论是本地容器运行还是发布到 Kubernetes这套集成都提供了统一的建模与编排体验。【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考