为了验证缓存是否生效,修改测试服务api/values/{id}代码,增加服务器时间输出。
[HttpGet("{id}")] public ActionResult<string> Get(int id) { return id+"-"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); }增加新的测试路由脚本,然后增加缓存策略,缓存60秒,缓存分类test_ahphocelot。
--插入路由测试信息 insert into AhphReRoute values(1,'/ctr/values/{id}','[ "GET" ]','','http','/api/Values/{id}','[{"Host": "localhost","Port": 9000 }]', '','','{ "TtlSeconds": 60, "Region": "test_ahphocelot" }','','','','',0,1); --插入网关关联表 insert into dbo.AhphConfigReRoutes values(1,2);现在我们测试访问网关地址:7777/api/values/1,过几十秒后继续访问,结果如下。
可以看出来,缓存已经生效,1分钟内请求都不会路由到服务端,再查询下redis缓存数据,发现缓存信息已经存在,然后使用Redis Desktop Manager查看Redis缓存信息是否存在,奈斯,已经存在,说明已经达到我们预期目的。
三、解决网关集群配置信息变更问题前面几篇已经介绍了网关的数据库存储,并介绍了网关的2种更新方式,但是如果网关集群部署时,采用接口更新方式,无法直接更新所有集群端配置数据,那如何实现集群配置信息一致呢?前面介绍了redis缓存,可以解决当前遇到的问题,我们需要重写内部配置文件提取仓储类,使用redis存储。
我们首先使用redis实现IInternalConfigurationRepository接口,每次请求配置信息时直接从redis存储,避免单机缓存出现数据无法更新的情况。RedisInternalConfigurationRepository代码如下。
using Ctr.AhphOcelot.Configuration; using Ocelot.Configuration; using Ocelot.Configuration.Repository; using Ocelot.Responses; using System; using System.Collections.Generic; using System.Text; namespace Ctr.AhphOcelot.Cache { /// <summary> /// 金焰的世界 /// 2018-11-14 /// 使用redis存储内部配置信息 /// </summary> public class RedisInternalConfigurationRepository : IInternalConfigurationRepository { private readonly AhphOcelotConfiguration _options; private IInternalConfiguration _internalConfiguration; public RedisInternalConfigurationRepository(AhphOcelotConfiguration options) { _options = options; CSRedis.CSRedisClient csredis; if (options.RedisConnectionStrings.Count == 1) { //普通模式 csredis = new CSRedis.CSRedisClient(options.RedisConnectionStrings[0]); } else { //集群模式 //实现思路:根据key.GetHashCode() % 节点总数量,确定连向的节点 //也可以自定义规则(第一个参数设置) csredis = new CSRedis.CSRedisClient(null, options.RedisConnectionStrings.ToArray()); } //初始化 RedisHelper RedisHelper.Initialization(csredis); } /// <summary> /// 设置配置信息 /// </summary> /// <param>配置信息</param> /// <returns></returns> public Response AddOrReplace(IInternalConfiguration internalConfiguration) { var key = _options.RedisKeyPrefix + "-internalConfiguration"; RedisHelper.Set(key, internalConfiguration.ToJson()); return new OkResponse(); } /// <summary> /// 从缓存中获取配置信息 /// </summary> /// <returns></returns> public Response<IInternalConfiguration> Get() { var key = _options.RedisKeyPrefix + "-internalConfiguration"; var result = RedisHelper.Get<InternalConfiguration>(key); if (result!=null) { return new OkResponse<IInternalConfiguration>(result); } return new OkResponse<IInternalConfiguration>(default(InternalConfiguration)); } } }redis实现后,然后在ServiceCollectionExtensions里增加接口实现注入。
builder.Services.AddSingleton<IInternalConfigurationRepository, RedisInternalConfigurationRepository>();然后启动网关测试,可以发现网关配置信息已经使用redis缓存了,可以解决集群部署后无法同步更新问题。
四、如何清除缓存记录实际项目使用过程中,可能会遇到需要立即清除缓存数据,那如何实现从网关清除缓存数据呢?在上篇中我们介绍了接口更新网关配置的说明,缓存的更新也是使用接口的方式进行删除,详细代码如下。
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Ocelot.Cache { [Authorize] [Route("outputcache")] public class OutputCacheController : Controller { private readonly IOcelotCache<CachedResponse> _cache; public OutputCacheController(IOcelotCache<CachedResponse> cache) { _cache = cache; } [HttpDelete] [Route("{region}")] public IActionResult Delete(string region) { _cache.ClearRegion(region); return new NoContentResult(); } } }