# 112. 基于 hystrix 完成对 redis 访问的资源隔离以避免缓存服务被拖垮

从本章开始,用几讲的时间,给咱们的 redis 访问这一块,加上保护措施,给商品服务的访问加上限流的保护措施(这里其实已经重复了,但是角度不一样,也就是场景不一样)

这里会使用之前的项目,就是有 storm 缓存预热的项目,那一套里面完成了之前的课程的知识点

redis 这一块,全都用 hystrix 的 command 进行封装,做资源隔离,确保 redis 的访问只能在固定的线程池内的资源来进行访问,哪怕是 redis 访问的很慢,有等待和超时也不要紧,只有少量额线程资源用来访问,缓存服务不会被拖垮

eshop-cache 项目中,对 redis 的操作有以下几个方法

// cn.mrcode.cachepdp.eshop.cache.service.impl.CacheServiceImpl#
saveProductInfo2RedisCache
getProductInfoOfRedisCache
saveShopInfo2RedisCache
getShopInfoOfRedisCache
1
2
3
4
5

把这几个方法修改成 hystrix 调用方式

添加依赖:compile 'com.netflix.hystrix:hystrix-core: 1.5.12'

上面四个方法,这里只贴出来其中一对,因为逻辑真的非常简单。

SaveProductInfo2RedisCommand.java

package cn.mrcode.cachepdp.eshop.cache.command;

import com.alibaba.fastjson.JSONObject;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;

import cn.mrcode.cachepdp.eshop.cache.model.ProductInfo;
import redis.clients.jedis.JedisCluster;

/**
 * @author : zhuqiang
 * @date : 2019/6/23 15:07
 */
public class SaveProductInfo2RedisCommand extends HystrixCommand<Boolean> {
    private JedisCluster jedisCluster;
    private final ProductInfo productInfo;

    public SaveProductInfo2RedisCommand(ProductInfo productInfo) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("SaveProductInfo2RedisCommand")));
        this.productInfo = productInfo;
    }

    @Override
    protected Boolean run() throws Exception {
        String key = "product_info_" + productInfo.getId();
        jedisCluster.set(key, JSONObject.toJSONString(productInfo));
        return true;
    }

    public JedisCluster getJedisCluster() {
        return jedisCluster;
    }

    public void setJedisCluster(JedisCluster jedisCluster) {
        this.jedisCluster = jedisCluster;
    }
}

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

调用处

/**
 * 将商品信息保存到redis中
 */
public void saveProductInfo2RedisCache(ProductInfo productInfo) {
//        String key = "product_info_" + productInfo.getId();
//        jedisCluster.set(key, JSONObject.toJSONString(productInfo));
    SaveProductInfo2RedisCommand command = new SaveProductInfo2RedisCommand(productInfo);
    command.setJedisCluster(jedisCluster);
    command.execute();
}
1
2
3
4
5
6
7
8
9
10

GetProductInfoOfRedisCommand.java

package cn.mrcode.cachepdp.eshop.cache.command;

import com.alibaba.fastjson.JSON;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;

import cn.mrcode.cachepdp.eshop.cache.model.ProductInfo;
import redis.clients.jedis.JedisCluster;

/**
 * @author : zhuqiang
 * @date : 2019/6/23 15:17
 */
public class GetProductInfoOfRedisCommand extends HystrixCommand<ProductInfo> {
    private JedisCluster jedisCluster;
    private Long productId;

    public GetProductInfoOfRedisCommand(Long productId) {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetProductInfoOfRedisCommand")));
        this.productId = productId;
    }

    @Override
    protected ProductInfo run() throws Exception {
        String key = "product_info_" + productId;
        String json = jedisCluster.get(key);
        return JSON.parseObject(json, ProductInfo.class);
    }

    public JedisCluster getJedisCluster() {
        return jedisCluster;
    }

    public void setJedisCluster(JedisCluster jedisCluster) {
        this.jedisCluster = jedisCluster;
    }
}
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

调用处

@Override
public ProductInfo getProductInfoOfRedisCache(Long productId) {
//        String key = "product_info_" + productId;
//        String json = jedisCluster.get(key);
//        return JSON.parseObject(json, ProductInfo.class);
    GetProductInfoOfRedisCommand command = new GetProductInfoOfRedisCommand(productId);
    command.setJedisCluster(jedisCluster);
    return command.execute();
}
1
2
3
4
5
6
7
8
9

启动项目后访问:http://localhost:6002/getProductInfo?productId=1 测试该方法的调用成功

可以看到只是把原有的逻辑放到 command 中去了,这里可以尝试使用 command 的注解,就不用这么麻烦的抽到类中了