通过Dapr实现一个简单的基于.net的微服务电商系统(十七)——服务保护之动态配置与热重载

  在上一篇文章里,我们通过注入sentinel component到apigateway实现了对下游服务的保护,不过受限于目前变更component需要人工的重新注入配置以及重启应用更新component等等原因,对于真实的环境运维稍有难度,最近我根据sentinel-golang相关文档重新编写了一个动态配置的功能并集成到了我们的电商demo管理端,今天就讲解并演示一下它是如何工作的。

目录:
一、通过Dapr实现一个简单的基于.net的微服务电商系统

二、通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解

三、通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr

四、通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布

五、通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理

六、通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务

七、通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流

八、通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪

九、通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权 && 百度版Oauth2

十、通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定

十一、通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容

十二、通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格

十三、通过Dapr实现一个简单的基于.net的微服务电商系统(十三)——istio+dapr构建多运行时服务网格之生产环境部署

十四、通过Dapr实现一个简单的基于.net的微服务电商系统(十四)——开发环境容器调试小技巧

十五、通过Dapr实现一个简单的基于.net的微服务电商系统(十五)——集中式接口文档实现

十六、通过Dapr实现一个简单的基于.net的微服务电商系统(十六)——dapr+sentinel中间件实现服务保护

十七、通过Dapr实现一个简单的基于.net的微服务电商系统(十七)——服务保护之动态配置与热重载

十八、通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存

十九、通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式

二十、通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享


附录:(如果你觉得对你有用,请给个star)
一、电商Demo地址

二、通讯框架地址

  首先我们看看最终效果如何,重新拉取代码并rebuild之后,登录admin.dapreshop.com:30882在基础配置新增了两个模块,其中swagger文档只是简单的对系列15文章中创建的集中式文档的简易集成。服务保护配置就是本次新增的部分了,其界面如下:

 

   当我们需要保护某个接口时,点击新增限流规则,并通过下拉选择我们的服务+路径即可配置一个规则,点击保存并重启网关会自动调用k8s进行component的重载并重启apigateway。

 

   在稍微等待20秒左右网关重启后(亦可通过使用kubectl get po -n dapreshop | findstr apigateway观察网关重启)即可通过并发测试来看看其效果。可以看到正确的对我们的接口产生了保护,也就是10秒内产生了100次左右的有效访问,剩余的访问被拦截并返回了429请求过多。

 

   在dapr的middleware-sentinel文档中可以看到还支持熔断降级、并发隔离、热点参数等等规则,不过目前测试过发现仅有服务限流规则拒绝类型的限流对dapr有效,其他规则暂时没有效果,不知道是不是dapr1.2的bug还是什么情况,已经github提了issuesl...

  下面简单讲讲如何实现热更新的。首先我们需要在apigateway注入一个空的sentinel config component:

复制代码
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: sentinel
  namespace: dapreshop
spec:
  type: middleware.http.sentinel
  version: v1
  metadata:
  - name: appName
    value: "rules"
  - name: logDir
    value: "/tmp"
  - name: flowRules
    value: >-
      []
  - name: circuitbreakerRules
    value: >-
      []
复制代码

  接着我在publicservice实现了热更新相关代码,具体代码在PublicService\Infrastructure\Common\AliSentinel中。通过引入了KubernetesClient的方式通过sdk操作component的读写以及deployment的更新。核心代码如下:

复制代码
 static Kubernetes kubernetes = new Kubernetes(KubernetesClientConfiguration.BuildConfigFromConfigFile(SentinelComponentBaseConfig.kubeconfig));
        /// <summary>
        /// 注册规则
        /// </summary>
        /// <param name="aliSentinelConfig"></param>
        public static async Task RegisterSentinelConfig(SentinelConfigList aliSentinelConfigList)
        {
            await GetAndSaveSentinelComponent(component =>
            {
                component.FlowRules = aliSentinelConfigList.FlowRules.GetDistinct();
                component.BreakingRules = aliSentinelConfigList.BreakingRules.GetDistinct();
            });
        }
        /// <summary>
        /// 获取所有注册规则
        /// </summary>
        /// <returns></returns>
        public static async Task<SentinelConfigList> GetAll()
        {
            var component = await GetDefaultSentinelComponent();
            return new SentinelConfigList()
            {
                FlowRules = component.FlowRules,
                BreakingRules = component.BreakingRules
            };
        }
        #region 本地方法
        /// <summary>
        /// 获取默认的SentinelComponent
        /// </summary>
        /// <returns></returns>
        static async Task<SentinelComponent> GetDefaultSentinelComponent()
        {
            var component = new SentinelComponent();
            await component.Create(kubernetes);
            return component;
        }
        /// <summary>
        /// 传递委托变更默认SentinelComponent
        /// </summary>
        /// <param name="operatorComponent"></param>
        static async Task GetAndSaveSentinelComponent(Action<SentinelComponent> operatorComponent)
        {
            var component = await GetDefaultSentinelComponent();
            operatorComponent(component);
            component.SetMetaData();
            Patch(component);
            ReloadDeploy();
        }
        /// <summary>
        /// Patch SentinelComponent到k8s环境
        /// </summary>
        /// <param name="component"></param>
        static void Patch(SentinelComponent component)
        {
            var patch = new JsonPatchDocument<SentinelComponent>();
            patch.Replace(x => x.spec.metadata, component.spec.metadata);
            kubernetes.PatchNamespacedCustomObject(new V1Patch(patch, V1Patch.PatchType.JsonPatch), SentinelComponentBaseConfig.Group, SentinelComponentBaseConfig.Version, SentinelComponentBaseConfig.NamespaceParameter, SentinelComponentBaseConfig.Plural, SentinelComponentBaseConfig.ComponentName);
        }
        /// <summary>
        /// 重启相关deploy更新SentinelComponent
        /// </summary>
        static void ReloadDeploy()
        {
            var deploy = kubernetes.ReadNamespacedDeployment(SentinelComponentBaseConfig.DeploymentName, SentinelComponentBaseConfig.NamespaceParameter);
            deploy.Spec.Template.Metadata.Annotations[SentinelComponentBaseConfig.restart] = DateTime.UtcNow.ToString("s");
            var patch = new JsonPatchDocument<V1Deployment>();
            patch.Replace(e => e.Spec.Template.Metadata.Annotations, deploy.Spec.Template.Metadata.Annotations);
            kubernetes.PatchNamespacedDeployment(new V1Patch(patch, V1Patch.PatchType.JsonPatch), SentinelComponentBaseConfig.DeploymentName, SentinelComponentBaseConfig.NamespaceParameter);
        }
复制代码

  接着我们在application暴露两个接口用于get component和save component。在页面上接入相关接口后即可正确的读取和写入component并滚动更新相关k8s资源从而实现热更新。整个限流流程大致如下:

 

   好了,今天的分享就到这里,照例欢迎fork+star~

posted @   a1010  阅读(1324)  评论(1编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示