Ocelot之缓存


 

 

Ocelot之缓存

前言

通过上节介绍Ocelot快速实践”后,了解了Ocelot网关,作为网关,要有很多功能才能满足要求,如缓存。

大家最普遍的理解就是当我们遇到某个页面打开很慢的时候,会想到引入缓存,这样页面打开就快了。

其实快和慢都是相对的,从技术角度来说,缓存之所以快是因为缓存是基于内存去建立的,而内存的读写速度比硬盘快 X 倍,所以用内存来代替硬盘作为读写的介质自然能大大提高访问数据的速度。

这个过程大致是这样的,通过在内存中存储被访问过的数据供后续访问时使用,以此来达到提速的效果。

环境:

VS2022 +.NET5.0 + Ocelot17.0.0.0

Ocelot缓存介绍

Ocelot中使用 CacheManager 来支持缓存,官方文档中强烈建议使用该包作为缓存工具。这是一个了不起的项目,它解决了很多缓存问题。 我会推荐这个软件包来做Ocelot缓存。 您可以使用CacheManager软件包支持的任何设置,只需传入即可。

无论如何,Ocelot目前支持对下游服务的URL进行缓存,并可以设置一个以秒为单位的TTL使缓存过期。 您也可以通过调用Ocelot的管理API来清除某个Region的缓存。


以下介绍通过使用CacheManager来实现Ocelot缓存。

添加CacheManager

Install-Package Ocelot.Cache.CacheManager

缓存是根据 downstream service URL来缓存的

FileCacheOptions选项几个参数

  • TtlSeconds - 缓存有效期,单位是秒
  • Region - 缓存分区,可以通过调用后台Api 来清空一个region下的缓存

项目演示

在上节Ocelot快速实践”项目基础上进行改造,实现的目标是在一分钟访问天气的数据都一样,也就是说一分钟内只访问了一次接口。项目机构如下:

2.1 运行接口服务

运行接口服务项目Yak.Ocelot.Api”。

2.2 修改Ocelot网关配置

配置如下:

  "Routes": [

    {

      "DownstreamPathTemplate": "/WeatherForecast",

      "DownstreamScheme": "http",

      "DownstreamHostAndPorts": [

        {

          "Host": "localhost",

          "Port": 6000

        }

      ],

      "UpstreamPathTemplate": "/Weather",

      "UpstreamHttpMethod": [ "Get" ],

      "FileCacheOptions": {

        "TtlSeconds": 60, //缓存时间(秒)

        "Region": "myRegion" //缓存区

      }

    }

  ],

  "GlobalConfiguration": {

    "BaseUrl": "https://localhost:5000"

  }

2.3 注入缓存组件

修改Startup文件的ConfigureServices代码,注入Ocelot缓存组件。

public void ConfigureServices(IServiceCollection services)

        {

            services.

                AddOcelot()

                .AddCacheManager(x => x.WithDictionaryHandle());//注入Ocelot缓存组件

        }

2.4 验证缓存

  1. 运行网关项目“Yak.Ocelot.Gateway”。

2.通过网关访问天气预报。

3.验证缓存

一分钟内多次访问接口http://localhost:5000/weather”时,数据没变化。

2.5 重写缓存

Ocelot提供了接口可以让我们重写缓存处理类,该类要实现 IOcelotCache接口,并且要在 Startup中的 ConfigureServices 方法中的 AddOcelot 之后添加 services.AddSingleton, MyCache>(); 来注入重写的缓存处理类覆盖Ocelot中默认的缓存处理。
如果需要实现文件缓存需要实现 IOcelotCache 接口并添加相应注入。

  1. 新建缓存处理类:

using Ocelot.Cache;

using System;

using System.Collections.Generic;

using System.Linq;

namespace Yak.Ocelot.Gateway

    public class MyOcelotCache : IOcelotCache

    {

        private static Dictionary _cacheObjs = new Dictionary();

        public void Add(string key, CachedResponse value, TimeSpan ttl, string region)

        {

            if (!_cacheObjs.ContainsKey($"{region}_{key}"))

            {

                _cacheObjs.Add($"{region}_{key}", new CacheObj()

                {

                    ExpireTime = DateTime.Now.Add(ttl),

                    Response = value

                });

            }

        }

        public CachedResponse Get(string key, string region)

        {

            if (!_cacheObjs.ContainsKey($"{region}_{key}")) return null;

            var cacheObj = _cacheObjs[$"{region}_{key}"];

            if (cacheObj != null && cacheObj.ExpireTime >= DateTime.Now)

            {

                return cacheObj.Response;

            }

            _cacheObjs.Remove($"{region}_{key}");

            return null;

        }

        public void ClearRegion(string region)

        {

            var keysToRemove = _cacheObjs.Where(c => c.Key.StartsWith($"{region}_"))

                .Select(c => c.Key)

                .ToList();

            foreach (var key in keysToRemove)

            {

                _cacheObjs.Remove(key);

            }

        }

        public void AddAndDelete(string key, CachedResponse value, TimeSpan ttl, string region)

        {

            if (_cacheObjs.ContainsKey($"{region}_{key}"))

            {

                _cacheObjs.Remove($"{region}_{key}");

            }

            _cacheObjs.Add($"{region}_{key}", new CacheObj()

            {

                ExpireTime = DateTime.Now.Add(ttl),

                Response = value

            });

        }

    }

    public class CacheObj

    {

        public DateTime ExpireTime { get; set; }

        public CachedResponse Response { get; set; }

    }

 2. 修改Startup文件的ConfigureServices代码,注入Ocelot缓存组件。

public void ConfigureServices(IServiceCollection services)

        {

            services.

                AddOcelot()

                .AddCacheManager(x => x.WithDictionaryHandle());//注入Ocelot缓存组件

        }

 3. 再次运行网关“Yak.Ocelot.Gateway”项目。1分钟之内天气数据仍然没变化,接口的Log显示一分钟内没有再次访问。

总结

网关是做缓存的一个好场所,毕竟网关是“业务无关性”的,它能够拦下来请求,对背后的源站也有很大的受益,减少了大量的 CPU 运算。

鸣谢

https://blog.csdn.net/qdwyj/article/details/119669238

http://t.zoukankan.com/lhxsoft-p-11724848.html

源码

https://github.com/yandaniugithub/NETCore