缓存优化
# 为什么使用缓存?
- 减少后端服务器压力:网关通常负责处理大量的请求流量,并将请求路由到后端的服务。通过在网关上使用缓存,可以避免重复的请求传递给后端服务,从而减轻后端服务的压力;
- 提高请求响应速度:缓存允许网关快速返回之前存储的响应,而无需再次向后端服务发起请求;
- 增强系统可用性:当后端服务发生故障或不可用时,缓存可以继续提供之前缓存的响应,保障系统的一部分功能仍然可用,有助于降低单点故障风险;
# Caffeine性能为什么更好?
# 分段锁
将缓存的键值对存储在多个分段中,每个分段独立加锁,以提高并发性;这使得在多线程环境下,多个线程可以同时读取不同的分段,从而减小了锁的粒度,提高了并发读取的性能;
# 内存淘汰策略
Window Tiny LFU算法,进一步提高了内存淘汰策略的效率和精确性;
W-TinyLFU 算法的主要特点和原理:
- 基于Counter的访问频率追踪: W-TinyLFU 和 TinyLFU 一样,通过使用计数器来追踪每个缓存项的访问频率。每个缓存项都有一个计数器,表示它被访问的次数。
- Adaptive Counting: W-TinyLFU 使用 Adaptive Counting(自适应计数)的方式,而不是传统的精确计数。Adaptive Counting 允许在占用更小空间的情况下估计元素的访问频率。这对于大规模的缓存系统来说是一种效率优化。
- 时间窗口: W-TinyLFU 引入了时间窗口的概念,将计数器的增加限制在一个固定的时间窗口内。这个时间窗口可以是固定大小的,也可以是根据缓存的大小和访问模式动态调整的。这样做的目的是适应访问模式的变化,让缓存更加灵活地适应不同的工作负载。
- 定期清零计数器: 在时间窗口的末尾,W-TinyLFU 对所有计数器进行一次定期清零操作。这意味着在每个时间窗口内,计数器只反映了最近一段时间内的访问情况。这样可以防止计数器过于陈旧,更好地适应动态变化的访问模式。
- 缓存淘汰策略: W-TinyLFU 根据计数器的值来选择淘汰缓存项。具有较低计数器值的缓存项更容易被淘汰,以保留访问频率较高的缓存项。
# 过滤器链缓存
根据固定的请求信息,缓存固定的过滤器链,避免每次请求进入后都需要根据完整的请求信息去构建过滤器链;
/**
* 使用Caffeine缓存 并且设定过期时间10min
*/
private Cache<String,GatewayFilterChain> chainCache = Caffeine.newBuilder().recordStats().expireAfterWrite(10, TimeUnit.MINUTES).build();
@Override
public GatewayFilterChain buildFilterChain(GatewayContext ctx) throws Exception {
return chainCache.get(ctx.getRule().getId(),k->doBuildFilterChain(ctx.getRule()));
}
public GatewayFilterChain doBuildFilterChain(Rule rule) {
GatewayFilterChain chain = new GatewayFilterChain();
List<Filter> filters = new ArrayList<>();
//filters.add(getFilterInfo(FilterConst.GRAY_FILTER_ID));
//filters.add(getFilterInfo(FilterConst.MONITOR_FILTER_ID));
//filters.add(getFilterInfo(FilterConst.MONITOR_END_FILTER_ID));
//filters.add(getFilterInfo(FilterConst.MOCK_FILTER_ID));
if(rule != null){
Set<Rule.FilterConfig> filterConfigs = rule.getFilterConfigs();
Iterator iterator = filterConfigs.iterator();
Rule.FilterConfig filterConfig;
while(iterator.hasNext()){
filterConfig = (Rule.FilterConfig)iterator.next();
if(filterConfig == null){
continue;
}
String filterId = filterConfig.getId();
if(StringUtils.isNotEmpty(filterId) && getFilterInfo(filterId) != null){
Filter filter = getFilterInfo(filterId);
filters.add(filter);
}
}
}
//添加路由过滤器-这是最后一步
filters.add(getFilterInfo(FilterConst.ROUTER_FILTER_ID));
//排序
filters.sort(Comparator.comparingInt(Filter::getOrder));
//添加到链表中
chain.addFilterList(filters);
return chain;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43