写点什么

Net DB Web 多级缓存的实现

  • 2023-07-04
    福建
  • 本文字数:2196 字

    阅读完需:约 7 分钟

1、客户端缓存(浏览器缓存)


HTTP 有一套控制缓存的协议-RFC7234,其中最重要的就是 cache-control 这个相应报文头,服务器返回时,如果 Response 带上


获取地址:http://www.jnpfsoft.com/?from=infoq


cache-control:max-age=5  #表示允许浏览器缓存5秒(仅是允许,浏览器是否缓存还看浏览器本身机制是否要遵循这套缓存协议)
复制代码


Net 封装好了一个缓存特性,如:


public class HomeController : ControllerBase    {        [ResponseCache(Duration = 5)]//告诉浏览器可用缓存5秒,Duration必须定义,不然请求会报错        [HttpGet("GetNowDateTime")]        public string GetNowDateTime()        {            return DateTime.Now.ToString();        }    }
复制代码


执行多次请求

  


第一行为首次请求,Response Headers:


cache-control: public,max-age=5   #告诉浏览器进行缓存content-encoding: gzipcontent-type: text/plain; charset=utf-8date: Sun, 19 Mar 2023 07:17:50 GMTserver: Microsoft-IIS/10.0vary: Accept-Encodingx-powered-by: ASP.NET
复制代码


后续 5s 内的请求,都会从缓存中取,Size=disk cache 即为缓存,取到的返回值和首次请求一致,直到过了 5s,再次向服务器发起请求。


PS:勾选 Disable cache,发出的请求头 Request Headers 会加上


cache-control: no-cache  #不从缓存中取数
复制代码


2、服务器端缓存


如果有大量客户端访问服务器获取数据,仅依靠客户端缓存,还是会让服务器多次运行接口程序


服务端缓存就是为了解决这个问题


.Net 添加服务器缓存中间件


//app.UseCors(); //跨域,如果有app.UseResponseCaching();//启动服务器缓存,位置介于这两中间件之间app.MapControllers();
复制代码


UseResponseCaching 中间件需要和 ResponseCache 特性配合使用


Api 代码仍为


public class HomeController : ControllerBase    {        [ResponseCache(Duration = 5)]//告诉浏览器可用缓存5秒        [HttpGet("GetNowDateTime")]        public string GetNowDateTime()        {            return DateTime.Now.ToString();        }    }
复制代码


打开两个浏览器访问尝试,功能实现!!!


不过,这种服务器缓存方式十分鸡肋,存在的限制太多:


a)无法解决恶意请求给服务器带来的压力(Request Header带上了cache-control: no-cache,不仅浏览器不读缓存,服务器也不读)b)响应码=200的Get或者Head的响应才会被缓存c)报文头带有Authorization、Set-Cookie等响应,不会缓存
复制代码


3、内存缓存


内存缓存需要自身在代码定义,仅针对业务层面的缓存,不受请求头影响


添加内存缓存服务


builder.Services.AddScoped<IDBHelper, SqlServerHelper>(); //db注入builder.Services.AddMemoryCache();//内存缓存
复制代码


模拟 SqlServerHelper 类


namespace DIDemo.Services{    public record Staff(int Id, string acc);    public class SqlServerHelper : IDBHelper    {        List<Staff> _staff_list = new List<Staff>();        public SqlServerHelper() {            _staff_list.Add(new Staff(1,"tom"));            _staff_list.Add(new Staff(2,"jerry"));        }public Staff? GetStaff(int Id)        {            return this._staff_list.Find(x => x.Id == Id);        }    }}
复制代码


定义一个查询员工的接口


using DIDemo.Services;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Caching.Memory;
namespace DIDemo.Controllers{ [Route("api/[controller]")] [ApiController] public class HomeController : ControllerBase { private readonly IDBHelper _db; private readonly IMemoryCache _menCache;
public HomeController(IDBHelper db, IMemoryCache menCache) { _db = db; _menCache = menCache; }
[HttpGet("GetStaff")] public ActionResult<Staff> GetStaff(int Id) { Console.WriteLine("begin"); //1、从缓存取数据 2、缓存取不到,从数据库取,添加缓存 var items = _menCache.GetOrCreate<Staff>($"staff_{Id}", (e) => { Console.WriteLine("缓存不存在,开始写缓存"); e.AbsoluteExpirationRelativeToNow= TimeSpan.FromSeconds(15); //15s后过期 e.SlidingExpiration = TimeSpan.FromSeconds(5); //5s滑动过期:5s内访问过缓存,会重新开始计算5s return _db.GetStaff(Id); }); if (items == null) { return NotFound($"员工ID={Id},不存在"); } return items; } }}
复制代码


GetOrCreate,如果获取不到,就通过委托,查询数据库并写入缓存


AbsoluteExpirationRelativeToNow:固定的过期时间


SlidingExpiration:滑动过期时间


两个时间可用单独定义,也可以一起定义,其中一个过期即为过期,通常不单独使用 SlidingExpiration,可能造成缓存无限续命


4、分布式缓存


涉及微服务,负载均衡,需要一个集中管理的缓存服务,也就是我们的分布式缓存


老生常谈的 Redis,看看以前写的文章吧!


文章转载自:wskxy

原文链接:https://www.cnblogs.com/wskxy/p/17233325.html

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Net DB Web多级缓存的实现_HTTP_不在线第一只蜗牛_InfoQ写作社区