ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

WebAPI性能优化小结

2022-07-22 22:36:21  阅读:182  来源: 互联网

标签:WebAPI 缓存 return redisConnection 小结 value key 优化 public


一、本地缓存

  • 设计思路

    查询数据时先查看本地缓存中是否有数据,如果有数据直接返回,如果没有数据,到数据库查询后添加到本地缓存,并将数据返回。

  • 优缺点

    • 缺点

      Memory是服务器内存的缓存,如果并发量大并查询的数据不一致,会造成内存非常大,同时会造成GC不断的回收内存,由于Memory内部使用的是静态变量,造成内存无法回收,GC每回收一次,就会耗费一次CPU资源,如果GC回收的频率比较大,大么耗费的CPU资源就较大。

      • 解决方案:1.设置缓存时间。2.设置缓存大小。
    • 优点

      数据读写速度时间缩短,性能提升。

  • 使用

    • 安装Nuget包

      Microsoft.Extensions.Caching.Memory

    • Startup.cs注册

      //ConfigureServices方法中注册缓存服务
      Service.AddMemoryCache(options=>{
      options.SizeLimit = 1024*1024*100; //设置缓存大小
      });
      
      
    • 使用方法

      //在构造方法中注入
      private readonly IMemoryCache memoryCache;
      构造函数 (IMemoryCache _memoryCache)
      {
      memoryCache =_memoryCache;
      }
      //测试对象
      Person per = new Person();
      //查询缓存方法
      //memoryCache.Get<Person>(key);
      //为了放防止多线程并发
      bool flag = memoryCache.TryGetValue<缓存对象>(key,out per);
      //true:有数据 false:无数据
      //限制缓存大小
      var cacheEntryOptions = new MemoryCacheEntryOptions().
      //设置单个缓存大下
      SetSize(1024).
      //设置过期时间 自动失效
      SetSlidingExpiration(TimeSpan.FromSeconds(3));
      //添加缓存
      memoryCache.Set<Person>(key,value,cacheEntryOptions);
      

二、分布式缓存

简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

  • 原理

    Redis数据库中的数据时存放在内存中,并非磁盘中,不需要把每次查询进行IO操作。把使用的数据查询加载的内存中,在内存中操作,提升查询效率。

  • 使用场景

    1.任何可丢失数据。2.不经常变动的数据。

  • 使用方式

    • 在appsetting.json添加Redis配置

      "ConnectionStrings: RedisCaching节点配置信息

      {
        "ConnectionStrings": {
          "ConnectionString": "Data Source=127.0.0.1;Initial Catalog=db;User ID=uid;Password=123456;Pooling=True;Max Pool Size=512;Connect Timeout=500;",
          "JwtSetting": {
            "Issuer": "jwtIssuer", //颁发者
            "Audience": "jwtAudience", //可以给哪些客户端使用
            "SecretKey": "chuangqianmingyueguang" //加密的Key
          },
          "RedisCaching": {
            "Enabled": true,
            "ConnectionString": "127.0.0.1:6379"
          }
        }
      }
      
    • 添加SerializeHelper.cs 对象序列化操作

      public class SerializeHelper
          {
              /// <summary>
              /// 序列化
              /// </summary>
              /// <param name="item"></param>
              /// <returns></returns>
              public static byte[] Serialize(object item)
              {
                  var jsonString = JsonConvert.SerializeObject(item);
      
                  return Encoding.UTF8.GetBytes(jsonString);
              }
              /// <summary>
              /// 反序列化
              /// </summary>
              /// <typeparam name="TEntity"></typeparam>
              /// <param name="value"></param>
              /// <returns></returns>
              public static TEntity Deserialize<TEntity>(byte[] value)
              {
                  if (value == null)
                  {
                      return default(TEntity);
                  }
                  var jsonString = Encoding.UTF8.GetString(value);
                  return JsonConvert.DeserializeObject<TEntity>(jsonString);
              }
          }
      
    • 定义接口和实现类

      新建IRedisCacheManager接口和RedisCacheManager类,并引用Nuget包StackExchange.Redis

       public class RedisCacheManager : IRedisCacheManager
          {
              private readonly string redisConnenctionString;
              public volatile ConnectionMultiplexer redisConnection;
              private readonly object redisConnectionLock = new object();
              public RedisCacheManager()
              {
                  string redisConfiguration = ConfigHelper.GetSectionValue("ConnectionStrings:RedisCaching:ConnectionString");//获取连接字符串
      
                  if (string.IsNullOrWhiteSpace(redisConfiguration))
                  {
                      throw new ArgumentException("redis config is empty", nameof(redisConfiguration));
                  }
                  this.redisConnenctionString = redisConfiguration;
                  this.redisConnection = GetRedisConnection();
              }
      
              /// <summary>
              /// 核心代码,获取连接实例
              /// 通过双if 夹lock的方式,实现单例模式
              /// </summary>
              /// <returns></returns>
              private ConnectionMultiplexer GetRedisConnection()
              {
                  //如果已经连接实例,直接返回
                  if (this.redisConnection != null && this.redisConnection.IsConnected)
                  {
                      return this.redisConnection;
                  }
                  //加锁,防止异步编程中,出现单例无效的问题
                  lock (redisConnectionLock)
                  {
                      if (this.redisConnection != null)
                      {
                          //释放redis连接
                          this.redisConnection.Dispose();
                      }
                      try
                      {
                          this.redisConnection = ConnectionMultiplexer.Connect(redisConnenctionString);
                      }
                      catch (Exception)
                      {
      
                          throw new Exception("Redis服务未启用,请开启该服务");
                      }
                  }
                  return this.redisConnection;
              }
      
              public void Clear()
              {
                  foreach (var endPoint in this.GetRedisConnection().GetEndPoints())
                  {
                      var server = this.GetRedisConnection().GetServer(endPoint);
                      foreach (var key in server.Keys())
                      {
                          redisConnection.GetDatabase().KeyDelete(key);
                      }
                  }
              }
      
              public bool Get(string key)
              {
                  return redisConnection.GetDatabase().KeyExists(key);
              }
      
              public string GetValue(string key)
              {
                  return redisConnection.GetDatabase().StringGet(key);
              }
      
              public TEntity Get<TEntity>(string key)
              {
                  var value = redisConnection.GetDatabase().StringGet(key);
                  if (value.HasValue)
                  {
                      //需要用的反序列化,将Redis存储的Byte[],进行反序列化
                      return SerializeHelper.Deserialize<TEntity>(value);
                  }
                  else
                  {
                      return default(TEntity);
                  }
              }
      
              public void Remove(string key)
              {
                  redisConnection.GetDatabase().KeyDelete(key);
              }
      
              public void Set(string key, object value, TimeSpan cacheTime)
              {
                  if (value != null)
                  {
                      //序列化,将object值生成RedisValue
                      redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime);
                  }
              }
      
              public bool SetValue(string key, byte[] value)
              {
                  return redisConnection.GetDatabase().StringSet(key, value, TimeSpan.FromSeconds(120));
              }
      
          }
      
    • 将Redis服务注入到容器中

      在ConfigureServices中 进行注入:

      //注册Redis
      services.AddSingleton<IRedisCacheManager, RedisCacheManager>();
      
    • 控制器中使用

      /// <summary>
      /// 测试Redis
      /// </summary>
      /// <returns></returns>
      [HttpGet]
      public async Task<IActionResult> Redis(int id)
      {
      
          var key = $"Redis{id}";
          UserNew user = new UserNew();
          if (_redisCacheManager.Get<object>(key) != null)
          {
              user = _redisCacheManager.Get<UserNew>(key);
          }
          else
          {
              user = new UserNew
              {
                  UserId = id,
                  UserName = "bingle",
                  Age = 18
              };
              _redisCacheManager.Set(key, user, TimeSpan.FromHours(2));//缓存2小时
          }
      
          return Ok(user);
      }
      

三、响应缓存

  • 原理

    当客户端第一次请求服务器,服务器响应后,服务器会往响应头里写入两个参数 :【1、是否开启缓存存储数据。2、校验】,并存储到客户端,客户端会将数据存储到缓存仓库中;当客户端第二次请求到服务器,会将etag传到服务器进行校验,如果两个etag是相等的,服务端会返给客户端304,客户端会从缓存仓库中获取数据。

  • 场景:

    不可变的数据使用。

  • 缺陷

    会浪费大量的客户端和服务器进行交互。

  • 协商缓存:

    • 安装Nuget包

      Marvin.Cache.Headers

    • 在Startup.cs中注册

      //ConfigureServices方法中注册
      Service.AddHttpCacheHeaders((options)=>{options.MaxAge = ....;//设置过期时间 默认60s
      options.CacheLocation = ....;//public 公共的 private 私有的只能当前客户端使用
      options.NoStore= ...;// 设置响应头信息 不走本地缓存
      options.NoTransform= ....;//设置请求头信息
      },
      (options1)=>{});
      //Configure方法中启动并存储校验信息
      app.UseHttpCacheHeaders();
      
    • 控制器中添加代码

      HttpContext.Response.Headers.Add("cache-control","max-age=60,public"); //是否开启缓存储数据 设置缓存时间
      HttpContext.Response.Headers.Add("etag",Value);//校验
      HttpContext.Response.Headers.Add("last-modified","Mon,24 Dec 2022 09:49:49 GMT");
      
  • 强制缓存:

    • 安装Nuget包:

    Marvin.Cache.Headers

    • 在Startup.cs中注册

      //ConfigureServices方法中注册
      Service.AddHttpCacheHeaders((options)=>{
      options.MustRevalidate = true; //全局的方式 不建议使用
      });
      //Configure方法中启动并存储校验信息
      app.UseHttpCacheHeaders();
      
    • 控制器中添加代码

      HttpContext.Response.Headers.Add("cache-control","max-age=60,public,must-revalidate");
      
    • 针对某个控制器使用

      //在控制器方法上添加特性
      [HttpCacheExpiration(CacheLocation = CacheLocation.Public,MaxAge=60)] 设置NoStore = true 不走缓存
      [HttpCacheValidation(MustRevalidate = true)]
      
    • 使用场景

      1.字典数据

      2.静态资源,如图片,视频,文本等。

      3.js或者css文件

四、数据压缩

  • 在Startup类ConfigureServices方法中注册

    //响应数据压缩
    services.AddResponseCompression();
    
  • 在Startup类Configure方法中开启服务

    //必须写在中间件的开头
    app.UseResponseCompression();
    
  • 数据压缩的目的

    传输数据的时候,减少数据传输的带宽,提升性能。

  • 场景

    只要涉及到数据传输,就可以进行压缩

标签:WebAPI,缓存,return,redisConnection,小结,value,key,优化,public
来源: https://www.cnblogs.com/wml-it/p/16508164.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有