优化TTFB 至500ms内

Posted 我爱你.代码+猪猪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优化TTFB 至500ms内相关的知识,希望对你有一定的参考价值。

继续上一篇《优化vue+springboot项目页面响应时间:waiting(TTFB) 及content Download》 优化TTFB 至500ms内

 

目前TTFB 接近1秒。再想优化,需要用到缓存技术,memcached或redis。

暂选择memcached,将查询数据写进内存,从内存中读取。

XMemcachedConfig.java

 package com.ruoyi.framework.config;
 
 import com.ruoyi.framework.config.properties.XMemcachedProperties;
 import net.rubyeye.xmemcached.MemcachedClient;
 import net.rubyeye.xmemcached.MemcachedClientBuilder;
 import net.rubyeye.xmemcached.XMemcachedClientBuilder;
 import net.rubyeye.xmemcached.command.BinaryCommandFactory;
 import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
 @Configuration
 public class XMemcachedConfig 
     @Autowired
     private XMemcachedProperties xMemcachedProperties;
 
     // 构建builder
     @Bean
     public MemcachedClientBuilder getXMemcachedBuilder() throws Exception
         MemcachedClientBuilder memcachedClientBuilder = null;
         try
 
            if ( !xMemcachedProperties.isOpenCache()) 
                return null;
            
             String servers = xMemcachedProperties.getServers();
             memcachedClientBuilder = new XMemcachedClientBuilder(servers);
             // 开启/关闭failure模式
             memcachedClientBuilder.setFailureMode(xMemcachedProperties.isFailureMode());
             memcachedClientBuilder.setSanitizeKeys(xMemcachedProperties.isSanitizeKeys());
             memcachedClientBuilder.setConnectionPoolSize(xMemcachedProperties.getPoolSize());
             memcachedClientBuilder.setCommandFactory(new BinaryCommandFactory());
             memcachedClientBuilder.setOpTimeout(xMemcachedProperties.getOperationTimeout());
             memcachedClientBuilder.setSessionLocator(new KetamaMemcachedSessionLocator());
 
             return memcachedClientBuilder;
         catch(Exception e)
             e.printStackTrace();
         
         return null;
     
 
     // client
     @Bean
     public MemcachedClient getXMemcachedClient(MemcachedClientBuilder memcachedClientBuilder) throws  Exception
         MemcachedClient memcachedClient = null;
         try
             memcachedClient = memcachedClientBuilder.build();
             return memcachedClient;
         catch(Exception e)
             e.printStackTrace();
         
         return null;
     
 

XMemcachedProperties.java

 package com.ruoyi.framework.config.properties;
 
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 
 @Component
 @ConfigurationProperties(prefix = "memcached")
 public class XMemcachedProperties 
 
     private String servers;
     private int poolSize;
     private boolean isSanitizeKeys;
     private boolean isOpenCache;
     private boolean isFailureMode;
     private long operationTimeout;
 
     public String getServers() 
         return servers;
     
 
     public void setServers(String servers) 
         this.servers = servers;
     
 
     public int getPoolSize() 
         return poolSize;
     
 
     public void setPoolSize(int poolSize) 
         this.poolSize = poolSize;
     
 
     public boolean isSanitizeKeys() 
         return isSanitizeKeys;
     
 
     public void setSanitizeKeys(boolean isSanitizeKeys) 
         this.isSanitizeKeys = isSanitizeKeys;
     
 
     public boolean isOpenCache() 
         return isOpenCache;
     
 
     public void setIsOpenCache(boolean isOpenCache) 
         this.isOpenCache = isOpenCache;
     
 
     public boolean isFailureMode() 
         return isFailureMode;
     
 
     public void setIsFailureMode(boolean isFailureMode) 
         this.isFailureMode = isFailureMode;
     
 
     public long getOperationTimeout() 
         return operationTimeout;
     
 
     public void setOperationTimeout(long operationTimeout) 
         this.operationTimeout = operationTimeout;
     
 

XMemcachedCache.java

 package com.ruoyi.common.core.xmemcached;
 
 import net.rubyeye.xmemcached.Counter;
 import net.rubyeye.xmemcached.MemcachedClient;
 import net.rubyeye.xmemcached.exception.MemcachedException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.io.IOException;
 import java.util.concurrent.TimeoutException;
 
 /**
  * @author x8023z
  */
 @Component
 public class XMemcachedCache 
 
     @Autowired
     private MemcachedClient memcachedClient;
     private static boolean isStatus;
 
     @Override
     protected void finalize()
     
         if (isStatus)
         
             try 
                 memcachedClient.shutdown();
              catch (IOException e) 
                 e.printStackTrace();
             
         
     
     /**
      * 永久缓存基本的对象,Integer、String、实体类等
      *
      * @param key 缓存的键值
      * @param value 缓存的值
      */
     public <T> void setCacheObject(final String key, final T value) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null) 
            isStatus = memcachedClient.set(key,0, value);
        
     
 
     /**
      * 缓存基本的对象,Integer、String、实体类等
      *
      * @param key 缓存的键值
      * @param value 缓存的值
      * @param timeout(单位毫秒),设置过期时间,如果expiredTime还未到期,timeout到期,则该memcached过期
      */
     public <T> void setCacheObject(final String key,  final T value, final long timeout) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null) 
             isStatus = memcachedClient.add(key, 0, value,timeout);
         
     
 
     /**
      * 添加缓存基本的对象,Integer、String、实体类等
      *
      * @param key 缓存的键值
      * @param expiredTime 时间 (单位秒),超过这个时间,memcached将这个数据替换出去,0表示永久存储(默认是一个月)
      * @param value 缓存的值
      * @param timeout(单位毫秒),设置过期时间,如果expiredTime还未到期,timeout到期,则该memcached过期
      */
     public <T> void setCacheObject(final String key, final Integer expiredTime, final T value, final long timeout) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null ) 
             isStatus = memcachedClient.add(key, expiredTime, value,timeout);
         
     
 
 
     /**
      * 替换缓存基本的对象,Integer、String、实体类等,注意类型是Object(统计切勿使用replace)
      *
      * @param key 缓存的键值
      * @param expiredTime 时间 (单位秒),超过这个时间,memcached将这个数据替换出去,0表示永久存储(默认是一个月)
      * @param value 缓存的值
      */
     public <T> void replaceCacheObject(final String key,  final Integer expiredTime, final T value) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null) 
             isStatus = memcachedClient.replace(key, expiredTime, value);
         
     
 
     /**
      * 替换缓存基本的对象,Integer、String、实体类等
      *
      * @param key 缓存的键值
      * @param expiredTime 时间 (单位秒),超过这个时间,memcached将这个数据替换出去,0表示永久存储(默认是一个月)
      * @param value 缓存的值
      * @param timeout(单位毫秒),设置过期时间,如果expiredTime还未到期,timeout到期,则该memcached过期
      */
     public <T> void replaceCacheObject(final String key, final Integer expiredTime, final T value, final long timeout) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null) 
             isStatus = memcachedClient.replace(key, expiredTime, value,timeout);
         
     
 
     /**
      * 永久替换缓存基本的对象,Integer、String、实体类等
      *
      * @param key 缓存的键值
      * @param value 缓存的值
      */
     public <T> void replaceCacheObject(final String key, final T value) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null) 
             isStatus = memcachedClient.replace(key,0, value);
         
     
 
     /**
      * 获得缓存的基本对象。
      *
      * @param key 缓存键值
      * @return 缓存键值对应的数据
      */
     public <T> T getCacheObject(final String key) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null) 
             return  memcachedClient.get(key);
          else 
             return null;
         
     
 
     /**
      * 删除缓存的基本对象。
      *
      * @param key 缓存键值
      */
     public <T> void deleteCacheObject(final String key) throws InterruptedException, TimeoutException, MemcachedException 
         if (memcachedClient != null) 
             isStatus = memcachedClient.delete(key);
         
     
 
 
     public <T> long getStats(final String key) throws InterruptedException, MemcachedException, TimeoutException 
         long reCount = -1;
         Counter counter = null;
         //第二个参数是计数器的初始值
         if (memcachedClient != null) 
             counter = memcachedClient.getCounter(key,-1);
         
         reCount = counter.get();
         //使用count时实质是在创建一个key,因此需要将这个key清除掉
         if(reCount == -1)
             deleteCacheObject(key);
         
         return  reCount;
     
 
 
     /**
      * 计数器累加extentOfIncrement
      * @param key 键
      * @param extentOfIncrement 递增的幅度大小
      * @param original key不存在的情况下的初始值
      * @return 计数
      */
     public <T> long addStats(String key, long extentOfIncrement, long original) throws InterruptedException, MemcachedException, TimeoutException 
         long reCount = -1;
         Counter counter = null;
         if (memcachedClient != null) 
            counter = memcachedClient.getCounter(key, original);
         
         counter.set(extentOfIncrement+original);
         reCount = counter.incrementAndGet();
         return  reCount;
     
 
     public <T> boolean getStatus()
     
         return isStatus;
     
 
 
 
 

application.yml

# memcached配置
memcached:
  servers: 127.0.0.1:11211
  poolSize: 10
  #是否启用url encode 机制
  sanitizeKeys: false
  # true为启动缓存 false为标准实现
  isOpenCache: true
  #是否开启失败模式,默认为false
  isFailureMode: false
  #接口操作的默认超时时间,可以被接口覆盖
  operationTimeout: 3000

修改优化之处

     @Autowired
     private XMemcachedCache memcachedcache;
 
     /**
      * 项目启动时,初始化参数到缓存,定时任务,每隔一分钟刷新缓存
      */
     @PostConstruct
     public void init() throws InterruptedException, TimeoutException, MemcachedException 
         loadingSysStreetCache();
     
 
     /**
      * 设置cache key
      *
      * @param sysStreetKey 参数键
      * @return 缓存键key
      */
     private String getSysStreetKey(String sysStreetKey)
     
         return Constants.SYS_STREET_KEY + sysStreetKey;
     
 
     /**
      * 加载所有省市区镇级缓存数据
      */
 
 
     public List<TreeNodeDict> loadingSysStreetCache() throws InterruptedException, TimeoutException, MemcachedException 
         List<SysStreet> list = streetService.selectStreetListView(new SysStreet());
         TreeDataConvertUtils tree = new TreeDataConvertUtils();
         List<TreeNodeDict> collect = list.stream()
                 .map(a-> new TreeNodeDict(a.getCode(), a.getName(), a.getProvinceCode()))
                 .collect(Collectors.toList());
 
         // 后台返回非树结构的list,前端处理慢
         // return AjaxResult.success(list);
         // 后台返回树结构list,前端处理快
         // return AjaxResult.success(tree.convertToTreeUseMap(collect,"1"));
 
         List<TreeNodeDict>  treeNodes =tree.convertToTreeUseMap(collect,"1");
         // 序列化
         if (memcachedcache != null) 
           memcachedcache.setCacheObject(getSysStreetKey(""), JSON.toJSONString(treeNodes));
         
         return treeNodes;
     
// 注意使用之时,返回前端需要反序列化
public AjaxResult listview(SysStreet street) throws InterruptedException, TimeoutException, MemcachedException
List<TreeNodeDict> listTreeNodeDict = null;
if (memcachedcache != null && memcachedcache.getStatus() )
// 反序列化
listTreeNodeDict = JSON.parseArray(memcachedcache.getCacheObject(getSysStreetKey("")), TreeNodeDict.class);

if (listTreeNodeDict == null || listTreeNodeDict.size() ==0 )

listTreeNodeDict = loadingSysStreetCache();


return AjaxResult.success(listTreeNodeDict);


优化结果:

 

以上是关于优化TTFB 至500ms内的主要内容,如果未能解决你的问题,请参考以下文章

Zappa django 响应时间

mysql中关于tmp_table_size的问题

从10s到300ms的接口优化,我做了哪些事

从20s优化到500ms,我用了这三招

从20s优化到500ms,我用了这三招

为啥我在使用本地 IIS 时等待 ttfb 的时间这么长?