首页 > 其他分享 >基于木舟平台浅谈surging 的热点KEY的解决方法

基于木舟平台浅谈surging 的热点KEY的解决方法

时间:2024-11-20 22:39:48浏览次数:1  
标签:缓存 Name Value Maps surging 浅谈 null Ref 木舟

 一、概述

      上篇文章介绍了基于surging的木舟平台如何构建起微服务 ,那么此篇文章将介绍基于木舟平台浅谈surging 的热点KEY的解决方法

      木舟 (Kayak) 是什么?

       木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。

      木舟kayal 平台开源地址:https://github.com/microsurging/

      surging 微服务引擎开源地址:https://github.com/fanliang11/surging(后面surging 会移动到microsurging进行维护)

 二、缓存热点Key的问题

  1. 什么是热点key的问题 就是某个瞬间有大量的请求去访问Redis上某个固定的key,导致缓存击穿,请求都打到了DB上,压垮了缓存服务和DB服务,从而影响到服务的可用性;
  2. 怎么样会成为热点Key

          (1)、 QPS 集中访问频次占比比较高的会被称为热点Key,木舟平台会添加基于routepath访问频次统计,让技术人员查找出排名靠前的热点KEY,

        (2)、Value数据集合非常大导致带宽占用比较高会被称为热点KEY.

         3.热点KEY的危害

          (1)、占用带宽影响其它服务调用

          (2)、请求过大,降低了其它缓存调用性能

           (3)、缓存击穿,DB被压垮,引起业务雪崩。

三、基于surging 如何解决热点Key的问题

       1.基于MemoryCache缓存拦截

     访问频次比较高,数据不经常修改,而无需其它微服务共享调用的时候就可以使用MemoryCache进行缓存在本地,就比如木舟平台首页的产品,设备,设备消息统计,如下图

 你可以添加以下特性就能开启缓存拦截,Mode选择CacheTargetType.MemoryCache

        [ServiceCacheIntercept(CachingMethod.Get, Key = "GetProductStatistics", CacheSectionType = "ddlCache", EnableL2Cache = false, Mode = CacheTargetType.MemoryCache, Time = 1, EnableStageCache = true)]
        Task<ApiResult<ProductStatisticsModel>> GetProductStatistics();

删除的时候就可以使用CachingMethod.Remove,传入"GetProducts", "GetProductStatistics", 如果需要传入其它参数值就可以添加_{0}_{1} ,比如 GetProductsByName_{0}

        [ServiceCacheIntercept(CachingMethod.Remove, "GetProducts", "GetProductStatistics", CacheSectionType = "ddlCache", Mode = CacheTargetType.MemoryCache, EnableStageCache = true)]
        [ServiceLogIntercept]
        Task<ApiResult<bool>> DeleteById(List<int> ids);

2. 基于redis 缓存

     访问频次比较高,数据不经常修改,但需其它微服务共享调用的时候就可以使用Redis进行缓存,就比如获取Token,就需要开启redis缓存拦截,可以在添加上添加,修改代码:Mode = CacheTargetType.Redis,如下图:

 

        [ServiceCacheIntercept(CachingMethod.Get, Key = "GetProductStatistics", CacheSectionType = "ddlCache", EnableL2Cache = false, Mode = CacheTargetType.Redis, Time = 1, EnableStageCache = true)]
        Task<ApiResult<ProductStatisticsModel>> GetProductStatistics();

 

3.二级缓存

访问频次比较高,数据会经常修改,Value数据集合非常大会导致占用带宽,这时候使用二级缓存是最适合的,因为大的数据集合会通过二级本地缓存读取,一级缓存存储标志位来管理二级缓存的失效,代码如下

        [Metadatas.ServiceCacheIntercept(Metadatas.CachingMethod.Get, Key = "GetUserId_{0}", CacheSectionType = "ddlCache", L2Key= "GetUserId_{0}",  EnableL2Cache = true, Mode = Metadatas.CacheTargetType.Redis, Time = 480,EnableStageCache =true)]

4. 缓存中间件的分片处理

缓存中间件使用了哈希一致性负载分流算法,这样就可以把不同的KEY分散到不同的服务节点上,也保证热点KEY的集中访问的问题,可以在cacheSettings配置文件中添加redis服务节点,配置文件代码如下:

{
  "CachingSettings": [
    {
      "Id": "ddlCache",
      "Class": "Surging.Core.Caching.RedisCache.RedisContext,Surging.Core.Caching",
      "InitMethod": "",
      "Maps": null,
      "Properties": [
        {
          "Name": "appRuleFile",
          "Ref": "rule",
          "Value": "",
          "Maps": null
        },
        {
          "Name": "dataContextPool",
          "Ref": "ddls_sample",
          "Value": "",
          "Maps": [
            {
              "Name": "Redis",
              "Properties": [
                {
                  "Name": null,
                  "Ref": null,
                  "Value": "127.0.0.1:6379::1",
                  "Maps": null
                },
                {
                  "Name": null,
                  "Ref": null,
                  "Value": "127.0.0.1:6379::1",
                  "Maps": null
                },
                {
                  "Name": null,
                  "Ref": null,
                  "Value": "127.0.0.1:6379::1",
                  "Maps": null
                }
              ]
            },
            {
              "Name": "MemoryCache",
              "Properties": null
            }
          ]
        },
        {
          "Name": "defaultExpireTime",
          "Ref": "",
          "Value": "120",
          "Maps": null
        },
        {
          "Name": "connectTimeout",
          "Ref": "",
          "Value": "120",
          "Maps": null
        },
        {
          "Name": "minSize",
          "Ref": "",
          "Value": "1",
          "Maps": null
        },
        {
          "Name": "maxSize",
          "Ref": "",
          "Value": "10",
          "Maps": null
        }
      ]
    },
    {
      "Id": "userCache",
      "Class": "Surging.Core.Caching.RedisCache.RedisContext,Surging.Core.Caching",
      "InitMethod": "",
      "Maps": null,
      "Properties": [
        {
          "Name": "appRuleFile",
          "Ref": "rule",
          "Value": "",
          "Maps": null
        },
        {
          "Name": "dataContextPool",
          "Ref": "ddls_sample",
          "Value": "",
          "Maps": [
            {
              "Name": "Redis",
              "Properties": [
                {
                  "Name": null,
                  "Ref": null,
                  "Value": "127.0.0.1:7000::1",
                  "Maps": null
                },
                {
                  "Name": null,
                  "Ref": null,
                  "Value": "127.0.0.1:7005::1",
                  "Maps": null
                },
                {
                  "Name": null,
                  "Ref": null,
                  "Value": "127.0.0.1:6379::1",
                  "Maps": null
                }
              ]
            },
            {
              "Name": "MemoryCache",
              "Properties": null
            }
          ]
        },
        {
          "Name": "defaultExpireTime",
          "Ref": "",
          "Value": "120",
          "Maps": null
        },
        {
          "Name": "connectTimeout",
          "Ref": "",
          "Value": "120",
          "Maps": null
        },
        {
          "Name": "minSize",
          "Ref": "",
          "Value": "1",
          "Maps": null
        },
        {
          "Name": "maxSize",
          "Ref": "",
          "Value": "10",
          "Maps": null
        }
      ]
    }
  ]
}

四、总结

  木舟平台api,ui已经开源发布,后面陆续更新,等完成mqtt和国标28181设备接入,会搭建官方网站和DEMO,敬请期待。

 

标签:缓存,Name,Value,Maps,surging,浅谈,null,Ref,木舟
From: https://www.cnblogs.com/fanliang11/p/18559532

相关文章

  • .NET Core 特性(Attribute)底层原理浅谈
    简介烂大街的资料不再赘述,简单来说就是给代码看的注释Attribute的使用场景Attribute不仅仅局限于C#中,在整个.NET框架中都提供了非常大的拓展点,任何地方都有Attribute的影子编译器层比如Obsolete,ConditionalC#层GET,POST,Max,Range,RequireCLRVM层StructLayout,DllImp......
  • 浅谈网络文件系统原理
    本文分享自天翼云开发者社区《浅谈网络文件系统原理》,作者:谢****云什么是网络文件系统?网络文件系统(NetworkFileSystem,NFS)实现了一种软件协议,能将远端的文件系统映射到本地,使用者访问网络上的文件就像在使用自己的计算机一样。远端是专属存储系统,通常称为NAS存储。比较出名的......
  • 网络-浅谈批量通讯和自主通讯的区别
    批量通信和自动通信是两种不同的通信概念,它们在多个方面存在显著的差异。以下是对这两种通信方式的详细解释:一、批量通信定义:批量通信通常指的是在数据通信过程中,将大量的数据或信息作为一个整体或批次进行传输。特点:高效性:由于数据是以整体或批次的形式进行传输,因此可以显著......
  • TYPE-C PD浅谈(四)
    TYPE-CPD浅谈(四)当对接识别完成后,Provider会先在VBUS上提供5V,接着会在CC脚位上送出SourceCapability(SRC_CAP),格式如下:内容定义了供电的各种选项,如共有几组电源可选,相对应的电压电流等。当Consumer接收到SRC_CAP封包后,会针对电源列表的内容,挑选一组电压,再发出需求指令给Provid......
  • 浅谈阅读
    似乎很小我就爱上阅读了。这份热爱如同种子般,在童年的心田里悄然生根发芽。每当翻开书页,如同推开了一扇通往新世界的大门,那里有奇幻的世界、深邃的哲学思考,还有无数令人着迷的故事和知识。阅读,成了我童年最宝贵的伴侣,它陪伴我度过了无数个静谧的午后和星光璀璨的夜晚。初三的日......
  • 鸿蒙NEXT开发教程:浅谈@ComponentV2装饰器
    听说今天的广州车展上有一部分人已经看到华为汽车的最后一“界”,尊界超豪华大轿车,应该很快就要正式亮相,可以期待一波。在api12之后,鸿蒙系统推出一个V2版本的状态管理装饰器,不过目前还在开发试用状态,幽蓝君仔细研究了一下,今天跟大家做一个简单的介绍。幽蓝君对V2版本装饰器的总结......
  • 浅谈线段树分治
    大体思想线段树分治是一种用于解决区间操作和时间点查询的算法。它的主要思想是以时间为下标建立线段树,将在某一时间段内生效的操作记录在线段树上,然后对于某一时间点的查询,可以直接从线段树上得到结果。线段树是一种容易维护区间的数据结构,它通过不断以中点分治区间,形成了\(log......
  • .NET Core 反射底层原理浅谈
    简介反射,反射,程序员的快乐。前期绑定与后期绑定在.NET中,前期绑定(EarlyBinding)是指在编译时就确定了对象的类型和方法,而后期绑定(LateBinding)或动态绑定是在运行时确定对象的类型和方法。前置知识:C#类型系统结构C#作为C++++,在类型系统上沿用C++的类型系统前期绑定在代......
  • .NET Core 泛型底层原理浅谈
    .NETCore泛型底层原理浅谈 简介泛型参考资料烂大街,基本资料不再赘述,比如泛型接口/委托/方法的使用,逆变与协变。泛型好处有如下几点代码重用算法重用,只需要预先定义好算法,排序,搜索,交换,比较等。任何类型都可以用同一套逻辑类型安全编译器保证不会将int传给string简单清......
  • .NET Core 委托底层原理浅谈
    简介.NET通过委托来提供回调函数机制,与C/C++不同的是,委托确保回调是类型安全,且允许多播委托。并支持调用静态/实例方法。简单来说,C++的函数指针有如下功能限制,委托作为C#中的上位替代,能弥补函数指针的不足。类型不安全函数指针可以指向一个方法定义完全不同的函数。在编译期......