优化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内的主要内容,如果未能解决你的问题,请参考以下文章