• Net DB Web多级缓存的实现


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

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

    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: gzip
    content-type: text/plain; charset=utf-8
    date: Sun, 19 Mar 2023 07:17:50 GMT
    server: Microsoft-IIS/10.0
    vary: Accept-Encoding
    x-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(); //db注入
    builder.Services.AddMemoryCache();//内存缓存

      模拟SqlServerHelper类

    复制代码
    namespace DIDemo.Services
    {
        public record Staff(int Id, string acc);
        public class SqlServerHelper : IDBHelper
        {
            List _staff_list = new List();
            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 GetStaff(int Id)
            {
                Console.WriteLine("begin");
                //1、从缓存取数据   2、缓存取不到,从数据库取,添加缓存
                var items =  _menCache.GetOrCreate($"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,看看以前写的文章吧!

      c# 使用 Redis   缓存Redis

     

  • 相关阅读:
    Mi小爱音箱pro接入GPT
    Visual Studio Code---介绍
    审查调试vue table show-overflow-tooltip样式
    理解 Objective-C 中 +load 方法的执行顺序
    OpenSceneGraph3.5.1编译
    yarn设置应用优先级
    Centos7下创建centos-home逻辑分区
    SpringBoot2运维实用篇(二)—— 配置高级
    .NET 表达式目录树
    VUE核心
  • 原文地址:https://www.cnblogs.com/wskxy/p/17233325.html