Skip to content

Commit a8ae6ff

Browse files
committed
added Efficiency
1 parent 40c7ecd commit a8ae6ff

File tree

15 files changed

+315
-10
lines changed

15 files changed

+315
-10
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,197 @@
11
# 优化网站性能
22

3+
- 本地缓存
4+
- 将数据缓存在应用服务器上,性能最好
5+
- 常用缓存工具:Ehcache, Guava, Caffeine等
6+
- 分布式缓存(仅比本地缓存多了网络开销)
7+
- 将数据缓存在NoSQL数据库上,跨服务器(比如登录凭证等)
8+
- 常用缓存工具:MemCache, Redis等
9+
- 多级缓存
10+
- 一级缓存(本地缓存) ==> 二级缓存(分布式缓存) ==> 三级缓存(DB)
11+
- 避免缓存雪崩(缓存失效,大量请求直达DB), 提高系统可用性
12+
13+
缓存示例:
14+
15+
![缓存](/imgs/efficience1.png)
16+
17+
多级缓存:若访问不到则级级向下找,直到找到DB,然后将DB数据级级向上缓存
18+
19+
![多级缓存](/imgs/efficiency.png)
20+
21+
缓存淘汰:详见计组的cache替换策略
22+
23+
## 代码实现
24+
25+
目标:优化热门帖子列表(随时间变化不大,隔一段时间才变一次)
26+
27+
使用本地缓存[Caffeine](https://github.com/ben-manes/caffeine)
28+
29+
1. 导包
30+
31+
```xml
32+
<dependency>
33+
<groupId>com.github.ben-manes.caffeine</groupId>
34+
<artifactId>caffeine</artifactId>
35+
</dependency>
36+
```
37+
38+
2. 自定义参数
39+
40+
在application.properties中:
41+
42+
```
43+
# caffeine
44+
caffeine.posts.max-size=15 # 仅缓存15个数据就够了,用户一般不会再往后看了
45+
caffeine.posts.expire-seconds=180 # 3分钟定时淘汰
46+
```
47+
48+
3. 优化Service方法,因为Controller最后调的都是Service
49+
50+
DiscussPostService:
51+
52+
```java
53+
@Value("${caffeine.posts.max-size}")
54+
private int maxSize;
55+
56+
@Value("${caffeine.posts.expire-seconds}")
57+
private int expireSeconds;
58+
59+
// 帖子列表(热帖)缓存
60+
private LoadingCache<String, List<DiscussPost>> postListCache;
61+
62+
// 缓存帖子总数
63+
private LoadingCache<Integer, Integer> postRowsCache;
64+
65+
// 初始化缓存
66+
@PostConstruct
67+
public void init(){
68+
postListCache = Caffeine.newBuilder()
69+
.maximumSize(maxSize)
70+
.expireAfterWrite(expireSeconds, TimeUnit.SECONDS)
71+
.build(new CacheLoader<String, List<DiscussPost>>() {
72+
@Override
73+
public @Nullable List<DiscussPost> load(String key) throws Exception { // load实质上查询了数据库
74+
if(key == null || key.length() ==0){
75+
throw new IllegalArgumentException("参数错误!");
76+
}
77+
String[] params = key.split(":");
78+
if(params == null && params.length != 2){
79+
throw new IllegalArgumentException("参数错误!");
80+
}
81+
int offset = Integer.parseInt(params[0]);
82+
int limit = Integer.parseInt(params[1]);
83+
84+
// 可以在这里访问redis建立多级缓存,如果没有数据再进入db查找
85+
86+
logger.debug("load post list from DB!");
87+
return discussPostMapper.selectDiscussPosts(0, offset, limit, 1);
88+
}
89+
});
90+
91+
postRowsCache = Caffeine.newBuilder()
92+
.maximumSize(maxSize)
93+
.expireAfterWrite(expireSeconds, TimeUnit.SECONDS)
94+
.build(new CacheLoader<Integer, Integer>() {
95+
@Override
96+
public @Nullable Integer load(Integer key) throws Exception {
97+
logger.debug("load post rows from DB !");
98+
return discussPostMapper.selectDiscussPostRows(key);
99+
}
100+
});
101+
}
102+
103+
public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit, int orderMode){
104+
// offset 和 limit 作为key标识一页
105+
if(userId == 0 && orderMode ==1){
106+
// 仅缓存热帖
107+
return postListCache.get(offset + ":" + limit); // 直接从缓存返回结果
108+
}
109+
logger.debug("load post list from DB!");
110+
return discussPostMapper.selectDiscussPosts(userId, offset,limit, orderMode);
111+
}
112+
113+
public int findDiscussPostRows(int userId){
114+
if(userId == 0){
115+
// 首页查询时缓存数量
116+
return postRowsCache.get(userId);
117+
}
118+
logger.debug("load post rows from DB !");
119+
return discussPostMapper.selectDiscussPostRows(userId);
120+
}
121+
```
122+
123+
Caffeine核心接口:Cache,LoadingCache(同步缓存),AsyncLoadingCache(异步缓存)
124+
125+
4. 测试类测试是否真的缓存了:
126+
127+
```java
128+
package com.nowcoder.community;
129+
130+
import com.nowcoder.community.entity.DiscussPost;
131+
import com.nowcoder.community.service.DiscussPostService;
132+
import org.junit.Test;
133+
import org.junit.runner.RunWith;
134+
import org.springframework.beans.factory.annotation.Autowired;
135+
import org.springframework.boot.test.context.SpringBootTest;
136+
import org.springframework.test.context.ContextConfiguration;
137+
import org.springframework.test.context.junit4.SpringRunner;
138+
139+
import java.util.Date;
140+
141+
@RunWith(SpringRunner.class)
142+
@SpringBootTest
143+
@ContextConfiguration(classes = CommunityApplication.class)
144+
public class CaffeineTests {
145+
@Autowired
146+
private DiscussPostService discussPostService;
147+
148+
@Test
149+
public void initDataForTest() { // 压力测试前置,先插入30w条数据,否则缓存的优势看不出来
150+
for (int i = 0; i < 300000; i++) {
151+
DiscussPost post = new DiscussPost();
152+
post.setUserId(111);
153+
post.setTitle("互联网求职暖春计划");
154+
post.setContent("压力测试!!!!");
155+
post.setCreateTime(new Date());
156+
post.setScore(Math.random() * 2000);
157+
discussPostService.addDiscussPost(post);
158+
}
159+
}
160+
161+
@Test
162+
public void testCache(){
163+
System.out.println(discussPostService.findDiscussPosts(0, 0, 10, 1));
164+
System.out.println(discussPostService.findDiscussPosts(0, 0, 10, 1));
165+
System.out.println(discussPostService.findDiscussPosts(0, 0, 10, 1));
166+
// 以上三次应该只访问一次数据库,即只输出一次logger-debug
167+
System.out.println(discussPostService.findDiscussPosts(0, 0, 10, 0));
168+
}
169+
}
170+
```
171+
172+
5. 压力测试——[JMeter](https://jmeter.apache.org/download_jmeter.cgi)
173+
174+
下载完成后进入bin目录双击jmeter.bat启动
175+
176+
jmeter配置如下测试:
177+
178+
![jmeter](/imgs/jmeter.png)
179+
180+
181+
![jmeter1](/imgs/jmeter1.png)
182+
183+
![jmeter2](/imgs/jmeter2.png)
184+
185+
![jmeter3](/imgs/jmeter3.png)
186+
187+
开始压力测试,主要关注吞吐量:
188+
189+
未用缓存:
190+
191+
![jmeter4](/imgs/jmeter4.png)
192+
193+
用了缓存:
194+
195+
![jmeter5](/imgs/jmeter5.png)
196+
197+
可以发现吞吐量显著提升,而且后台的sql日志仅输出了一次

imgs/efficience1.png

308 KB
Loading

imgs/efficiency.png

243 KB
Loading

imgs/jmeter.png

125 KB
Loading

imgs/jmeter1.png

143 KB
Loading

imgs/jmeter2.png

101 KB
Loading

imgs/jmeter3.png

139 KB
Loading

imgs/jmeter4.png

151 KB
Loading

imgs/jmeter5.png

149 KB
Loading

pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@
126126
<artifactId>qiniu-java-sdk</artifactId>
127127
<version>7.2.23</version>
128128
</dependency>
129+
<dependency>
130+
<groupId>com.github.ben-manes.caffeine</groupId>
131+
<artifactId>caffeine</artifactId>
132+
</dependency>
129133
</dependencies>
130134

131135
<build>

0 commit comments

Comments
 (0)