缓存取数服务目前仅保留单一只能对外输出缓存数据,因此对他的性能要求期望是很高的,虽然使用的redis作为存储介质,但由于存在一些单key缓存数据比较大等问题,一开始缓存取数取数服务性能并不高

    这里记录些还记得的优化过的地方

    • 一开始就换掉原来阻塞请求的spingMVC,改用webFlux的reactor模型 这样并没有提升实质性的性能,但为高吞吐量奠定基石
    • 代码质量优化,取数据的流程代码,严格按照Java代码开发规范,像能不创建对象就不创建对象,省略不必要的操作,不能存在魔法值等等
    • 尽量使用单例,使用字符串常量,字符类型虽然好用但其操作其实是所有类型最吃性能的,其思想是在保证业务正确前提下把能准备的事情都给做掉

    下面的就需要研究业务项目才能发现

    • 使用reactor模型非必要一定不要阻塞操作,尽量使用其提供的策略像Supplier等懒式方法
    • 存储结构改动,首先redis 内存是宝贵的想压缩存储数据
      • 早前沿用前人的一版,大概流程
      • 从数据源取回数据 -》序列化为JSON形式-》String转二进制-》二进制GZIP压缩-》二进制用自写算法(不知道哪抄的)编码成String -》String存储redis(这个过程还要String 转二进制)
      • 这个过程业务可用没问题但本身就很繁琐,我推测其目的
        • 只知道redis的Value只能存字符串如果直接用压缩的二进制toString,取回来的时候不知道怎么再转回来
        • 知道Value可存二进制,但直接存二进制担心安全问题,像某些数据库存二进制是非安全类型,会改变其内容,就必须存String的Value
      • 我第一次优化这个流程没考虑清楚存二进制的问题,只做了二进制用自学写算法这块优化,首先发现这个自写算法性能不高并且编码的结果也比较大,然后改用成JDK8以后新增神器Base64来搞,并且在切入时机取巧少了两次toByte过程,这样存储大小已经有了大幅减少,但其实只要编码就依然会增大内存
      • 后边深入研究后最终优化流程
        • 从数据源取回数据 -》序列化为JSON形式-》String转二进制-》二进制GZIP压缩-》二进制直接存Redis
        • 这个过程少了Base64及String、二进制之间的各种转化,直接存压缩后的二进制,其本质就是抓住了Redis可以直接存二进制而且是安全类,整个过程只有一个Gzip压缩的过程
    • redisClient改动
      • 首先springBoot 二点几之后redis客户端默认都用Lettuce,这就说明了这款客户端是优秀的,而我用的ReactiveRedis也必须使用Lettuce才能支持
      • 这个Client前前后后其实改了很多次,有用SpringBoot AutoConfiguer,也有用自己配置但其实最后都无所谓的,主要是要了解里边的过程,这里记录大概过程
      • 我先是自己写连接配置主动配置了 Netty的IOThread、ComputationThread这些默认是CPU核数
      • 后来翻源码发现Lettuce的 Netty默认情况下就是单线连接其实是单实例,(这其实nettyIO多路复用的思想,所谓的零拷贝)但流程中的NioEpollEvent可以调整可以配置成多线程,至此如果是不经常那么依赖redis,IO不存在瓶颈情况下,目前的配置是最合适的,网上找各种资料,也是认为这样配置的,能充分发挥redis Netty连接优势
      • 但上线请求单机300qps存在性能瓶颈,CPU只能用到60%3H吞吐量上不去了,经过一番调查,Netty的单连接卡瓶颈了,随后发现了有相关地方可以改连接实例,调整连接数,使用连接池
        • 具体改动为在创建LettuceFactory时需要将ShareNativeConetion默认值true改为False
        • 最后我用的是AutoConfigure
          • spring.redis.lettuce.pool.max-active=350

    spring.redis.lettuce.pool.min-idle=100
    spring.redis.lettuce.pool.max-idle=320
    spring.redis.lettuce.pool.max-wait=2000
    spring.redis.lettuce.pool.time-between-eviction-runs=-1

    1. - 注意最后一个参数必须是负数,意为保持长连接不中断,不然对于我这种频繁使用redis业务,会被搞死
    2. - 因为使用了AutoConfigureNetty相关的配置就不能直接在代码中配置了,但可以在JVM参数中配置,其实只要配置一个就够了 -Dio.netty.eventLoopThreads=15

    整体提升效果
    不算上前期效果,只看最近一版

    • redis内存减低百分之二十, 从单台980M到770M 共4台,减少800M内存使用
    • CPU使用从单台支撑300QPS 用2.8H 降低到 1H
    • 响应时间从单台峰值400qps时段 平均耗时从 18ms 降低到 3ms 从Sentinel 实时计算拿到数据