优化TTFB 至500ms内

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

 

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

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

XMemcachedConfig.java

 1 package com.ruoyi.framework.config;
 2 
 3 import com.ruoyi.framework.config.properties.XMemcachedProperties;
 4 import net.rubyeye.xmemcached.MemcachedClient;
 5 import net.rubyeye.xmemcached.MemcachedClientBuilder;
 6 import net.rubyeye.xmemcached.XMemcachedClientBuilder;
 7 import net.rubyeye.xmemcached.command.BinaryCommandFactory;
 8 import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
 9 import org.springframework.beans.factory.annotation.Autowired;
10 import org.springframework.context.annotation.Bean;
11 import org.springframework.context.annotation.Configuration;
12 
13 @Configuration
14 public class XMemcachedConfig {
15     @Autowired
16     private XMemcachedProperties xMemcachedProperties;
17 
18     // 构建builder
19     @Bean
20     public MemcachedClientBuilder getXMemcachedBuilder() throws Exception{
21         MemcachedClientBuilder memcachedClientBuilder = null;
22         try{
23 
24            if ( !xMemcachedProperties.isOpenCache()) {
25                return null;
26            }
27             String servers = xMemcachedProperties.getServers();
28             memcachedClientBuilder = new XMemcachedClientBuilder(servers);
29             // 开启/关闭failure模式
30             memcachedClientBuilder.setFailureMode(xMemcachedProperties.isFailureMode());
31             memcachedClientBuilder.setSanitizeKeys(xMemcachedProperties.isSanitizeKeys());
32             memcachedClientBuilder.setConnectionPoolSize(xMemcachedProperties.getPoolSize());
33             memcachedClientBuilder.setCommandFactory(new BinaryCommandFactory());
34             memcachedClientBuilder.setOpTimeout(xMemcachedProperties.getOperationTimeout());
35             memcachedClientBuilder.setSessionLocator(new KetamaMemcachedSessionLocator());
36 
37             return memcachedClientBuilder;
38         }catch(Exception e){
39             e.printStackTrace();
40         }
41         return null;
42     }
43 
44     // client
45     @Bean
46     public MemcachedClient getXMemcachedClient(MemcachedClientBuilder memcachedClientBuilder) throws  Exception{
47         MemcachedClient memcachedClient = null;
48         try{
49             memcachedClient = memcachedClientBuilder.build();
50             return memcachedClient;
51         }catch(Exception e){
52             e.printStackTrace();
53         }
54         return null;
55     }
56 }
View Code

XMemcachedProperties.java

 1 package com.ruoyi.framework.config.properties;
 2 
 3 import org.springframework.boot.context.properties.ConfigurationProperties;
 4 import org.springframework.stereotype.Component;
 5 
 6 @Component
 7 @ConfigurationProperties(prefix = "memcached")
 8 public class XMemcachedProperties {
 9 
10     private String servers;
11     private int poolSize;
12     private boolean isSanitizeKeys;
13     private boolean isOpenCache;
14     private boolean isFailureMode;
15     private long operationTimeout;
16 
17     public String getServers() {
18         return servers;
19     }
20 
21     public void setServers(String servers) {
22         this.servers = servers;
23     }
24 
25     public int getPoolSize() {
26         return poolSize;
27     }
28 
29     public void setPoolSize(int poolSize) {
30         this.poolSize = poolSize;
31     }
32 
33     public boolean isSanitizeKeys() {
34         return isSanitizeKeys;
35     }
36 
37     public void setSanitizeKeys(boolean isSanitizeKeys) {
38         this.isSanitizeKeys = isSanitizeKeys;
39     }
40 
41     public boolean isOpenCache() {
42         return isOpenCache;
43     }
44 
45     public void setIsOpenCache(boolean isOpenCache) {
46         this.isOpenCache = isOpenCache;
47     }
48 
49     public boolean isFailureMode() {
50         return isFailureMode;
51     }
52 
53     public void setIsFailureMode(boolean isFailureMode) {
54         this.isFailureMode = isFailureMode;
55     }
56 
57     public long getOperationTimeout() {
58         return operationTimeout;
59     }
60 
61     public void setOperationTimeout(long operationTimeout) {
62         this.operationTimeout = operationTimeout;
63     }
64 }
View Code

XMemcachedCache.java

  1 package com.ruoyi.common.core.xmemcached;
  2 
  3 import net.rubyeye.xmemcached.Counter;
  4 import net.rubyeye.xmemcached.MemcachedClient;
  5 import net.rubyeye.xmemcached.exception.MemcachedException;
  6 import org.springframework.beans.factory.annotation.Autowired;
  7 import org.springframework.stereotype.Component;
  8 
  9 import java.io.IOException;
 10 import java.util.concurrent.TimeoutException;
 11 
 12 /**
 13  * @author x8023z
 14  */
 15 @Component
 16 public class XMemcachedCache {
 17 
 18     @Autowired
 19     private MemcachedClient memcachedClient;
 20     private static boolean isStatus;
 21 
 22     @Override
 23     protected void finalize()
 24     {
 25         if (isStatus)
 26         {
 27             try {
 28                 memcachedClient.shutdown();
 29             } catch (IOException e) {
 30                 e.printStackTrace();
 31             }
 32         }
 33     }
 34     /**
 35      * 永久缓存基本的对象,Integer、String、实体类等
 36      *
 37      * @param key 缓存的键值
 38      * @param value 缓存的值
 39      */
 40     public <T> void setCacheObject(final String key, final T value) throws InterruptedException, TimeoutException, MemcachedException {
 41         if (memcachedClient != null) {
 42            isStatus = memcachedClient.set(key,0, value);
 43        }
 44     }
 45 
 46     /**
 47      * 缓存基本的对象,Integer、String、实体类等
 48      *
 49      * @param key 缓存的键值
 50      * @param value 缓存的值
 51      * @param timeout(单位毫秒),设置过期时间,如果expiredTime还未到期,timeout到期,则该memcached过期
 52      */
 53     public <T> void setCacheObject(final String key,  final T value, final long timeout) throws InterruptedException, TimeoutException, MemcachedException {
 54         if (memcachedClient != null) {
 55             isStatus = memcachedClient.add(key, 0, value,timeout);
 56         }
 57     }
 58 
 59     /**
 60      * 添加缓存基本的对象,Integer、String、实体类等
 61      *
 62      * @param key 缓存的键值
 63      * @param expiredTime 时间 (单位秒),超过这个时间,memcached将这个数据替换出去,0表示永久存储(默认是一个月)
 64      * @param value 缓存的值
 65      * @param timeout(单位毫秒),设置过期时间,如果expiredTime还未到期,timeout到期,则该memcached过期
 66      */
 67     public <T> void setCacheObject(final String key, final Integer expiredTime, final T value, final long timeout) throws InterruptedException, TimeoutException, MemcachedException {
 68         if (memcachedClient != null ) {
 69             isStatus = memcachedClient.add(key, expiredTime, value,timeout);
 70         }
 71     }
 72 
 73 
 74     /**
 75      * 替换缓存基本的对象,Integer、String、实体类等,注意类型是Object(统计切勿使用replace)
 76      *
 77      * @param key 缓存的键值
 78      * @param expiredTime 时间 (单位秒),超过这个时间,memcached将这个数据替换出去,0表示永久存储(默认是一个月)
 79      * @param value 缓存的值
 80      */
 81     public <T> void replaceCacheObject(final String key,  final Integer expiredTime, final T value) throws InterruptedException, TimeoutException, MemcachedException {
 82         if (memcachedClient != null) {
 83             isStatus = memcachedClient.replace(key, expiredTime, value);
 84         }
 85     }
 86 
 87     /**
 88      * 替换缓存基本的对象,Integer、String、实体类等
 89      *
 90      * @param key 缓存的键值
 91      * @param expiredTime 时间 (单位秒),超过这个时间,memcached将这个数据替换出去,0表示永久存储(默认是一个月)
 92      * @param value 缓存的值
 93      * @param timeout(单位毫秒),设置过期时间,如果expiredTime还未到期,timeout到期,则该memcached过期
 94      */
 95     public <T> void replaceCacheObject(final String key, final Integer expiredTime, final T value, final long timeout) throws InterruptedException, TimeoutException, MemcachedException {
 96         if (memcachedClient != null) {
 97             isStatus = memcachedClient.replace(key, expiredTime, value,timeout);
 98         }
 99     }
100 
101     /**
102      * 永久替换缓存基本的对象,Integer、String、实体类等
103      *
104      * @param key 缓存的键值
105      * @param value 缓存的值
106      */
107     public <T> void replaceCacheObject(final String key, final T value) throws InterruptedException, TimeoutException, MemcachedException {
108         if (memcachedClient != null) {
109             isStatus = memcachedClient.replace(key,0, value);
110         }
111     }
112 
113     /**
114      * 获得缓存的基本对象。
115      *
116      * @param key 缓存键值
117      * @return 缓存键值对应的数据
118      */
119     public <T> T getCacheObject(final String key) throws InterruptedException, TimeoutException, MemcachedException {
120         if (memcachedClient != null) {
121             return  memcachedClient.get(key);
122         } else {
123             return null;
124         }
125     }
126 
127     /**
128      * 删除缓存的基本对象。
129      *
130      * @param key 缓存键值
131      */
132     public <T> void deleteCacheObject(final String key) throws InterruptedException, TimeoutException, MemcachedException {
133         if (memcachedClient != null) {
134             isStatus = memcachedClient.delete(key);
135         }
136     }
137 
138 
139     public <T> long getStats(final String key) throws InterruptedException, MemcachedException, TimeoutException {
140         long reCount = -1;
141         Counter counter = null;
142         //第二个参数是计数器的初始值
143         if (memcachedClient != null) {
144             counter = memcachedClient.getCounter(key,-1);
145         }
146         reCount = counter.get();
147         //使用count时实质是在创建一个key,因此需要将这个key清除掉
148         if(reCount == -1){
149             deleteCacheObject(key);
150         }
151         return  reCount;
152     }
153 
154 
155     /**
156      * 计数器累加extentOfIncrement
157      * @param key 键
158      * @param extentOfIncrement 递增的幅度大小
159      * @param original key不存在的情况下的初始值
160      * @return 计数
161      */
162     public <T> long addStats(String key, long extentOfIncrement, long original) throws InterruptedException, MemcachedException, TimeoutException {
163         long reCount = -1;
164         Counter counter = null;
165         if (memcachedClient != null) {
166            counter = memcachedClient.getCounter(key, original);
167         }
168         counter.set(extentOfIncrement+original);
169         reCount = counter.incrementAndGet();
170         return  reCount;
171     }
172 
173     public <T> boolean getStatus()
174     {
175         return isStatus;
176     }
177 
178 
179 
180 }
View Code

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

修改优化之处

 1     @Autowired
 2     private XMemcachedCache memcachedcache;
 3 
 4     /**
 5      * 项目启动时,初始化参数到缓存,定时任务,每隔一分钟刷新缓存
 6      */
 7     @PostConstruct
 8     public void init() throws InterruptedException, TimeoutException, MemcachedException {
 9         loadingSysStreetCache();
10     }
11 
12     /**
13      * 设置cache key
14      *
15      * @param sysStreetKey 参数键
16      * @return 缓存键key
17      */
18     private String getSysStreetKey(String sysStreetKey)
19     {
20         return Constants.SYS_STREET_KEY + sysStreetKey;
21     }
22 
23     /**
24      * 加载所有省市区镇级缓存数据
25      */
26 
27 
28     public List<TreeNodeDict> loadingSysStreetCache() throws InterruptedException, TimeoutException, MemcachedException {
29         List<SysStreet> list = streetService.selectStreetListView(new SysStreet());
30         TreeDataConvertUtils tree = new TreeDataConvertUtils();
31         List<TreeNodeDict> collect = list.stream()
32                 .map(a-> new TreeNodeDict(a.getCode(), a.getName(), a.getProvinceCode()))
33                 .collect(Collectors.toList());
34 
35         // 后台返回非树结构的list,前端处理慢
36         // return AjaxResult.success(list);
37         // 后台返回树结构list,前端处理快
38         // return AjaxResult.success(tree.convertToTreeUseMap(collect,"1"));
39 
40         List<TreeNodeDict>  treeNodes =tree.convertToTreeUseMap(collect,"1");
41         // 序列化
42         if (memcachedcache != null) {
43           memcachedcache.setCacheObject(getSysStreetKey(""), JSON.toJSONString(treeNodes));
44         }
45         return treeNodes;
46     }
View Code
// 注意使用之时,返回前端需要反序列化
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);
}

优化结果:

 

posted @ 2022-01-04 20:12  HiEagle  阅读(225)  评论(0编辑  收藏  举报