JAVA数据库淘淘商城项目

Redis集群和缓存

2018-05-21  本文已影响20人  WebGiser

1、安装redis

安装的前提条件:
需要安装gcc:yum install gcc-c++
1、下载redis的源码包。
2、把源码包上传到linux服务器
3、解压源码包:tar -zxvf redis-3.0.0.tar.gz
4、Make
5、Make install:[root@bogon redis-3.0.0]# make install PREFIX=/usr/local/redis

2、启动redis

1、前端启动模式
/usr/local/redis/bin/redis-server
默认是前端启动模式,端口是6379

2、后端启动
1)从redis的源码目录中复制redis.conf到redis的安装目录。
2)修改配置文件


image.png

3)[root@bogon bin]# ./redis-server redis.conf

3、Redis常用命令

127.0.0.1:6379> set a 10
OK
127.0.0.1:6379> get a
"10"

4、集群结构

集群中有三个节点的集群,每个节点有一主一备。需要6台虚拟机。
搭建一个伪分布式的集群,使用6个redis实例来模拟。

1、搭建集群需要的环境
搭建集群需要使用到官方提供的ruby脚本。需要安装ruby的环境。
安装ruby
yum install ruby
yum install rubygems

redis集群管理工具redis-trib.rb
[root@bogon ~]# cd redis-3.0.0
[root@bogon redis-3.0.0]# cd src
[root@bogon src]# ll *.rb
-rwxrwxr-x. 1 root root 48141 Apr 1 07:01 redis-trib.rb

脚本需要的ruby包:


image.png

需要上传到linux服务。
安装ruby的包:
[root@bogon ~]# gem install redis-3.0.0.gem

2、集群的搭建
第一步:创建6个redis实例,端口号从7001~7006
第二步:修改redis的配置文件
1、修改端口号

image.png
2、打开cluster-enable前面的注释。
image.png
第三步:把创建集群的ruby脚本redis-trib.rb复制到redis-cluster目录下。
第四步:启动6个redis实例
第五步:创建集群。
[root@bogon redis-cluster]# ./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005 192.168.25.153:7006

3、集群测试
[root@bogon redis-cluster]# redis01/redis-cli -h 192.168.25.153 -p 7002 -c
192.168.25.153:7002> set a 100
-> Redirected to slot [15495] located at 192.168.25.153:7003
OK

5、Jedis客户端

需要把jedis的jar包添加到工程中,如果是maven需要添加jar包的坐标。

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.2</version>
        </dependency>

1、单机版

     /**
     * redis单机版测试
     */
    @Test
    public void testJedisSingle(){
        Jedis jedis = new Jedis("10.10.1.146",6379);
        jedis.set("name","abc");
        String name = jedis.get("name");
        System.out.println(name);
        jedis.close();
    }
    /**
     * redis连接池测试
     */
    @Test
    public void testJedisPool(){
        JedisPool pool = new JedisPool("10.10.1.146",6379);
        Jedis jedis = pool.getResource();
        jedis.set("age","100");
        String age = jedis.get("age");
        System.out.println(age);
        jedis.close();
        pool.close();
    }

2、集群版

    /**
     * redis集群测试(自带连接池)
     */
    @Test
    public void testJedisCluster(){
        //添加节点
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("10.10.1.146",7001));
        nodes.add(new HostAndPort("10.10.1.146",7002));
        nodes.add(new HostAndPort("10.10.1.146",7003));
        nodes.add(new HostAndPort("10.10.1.146",7004));
        nodes.add(new HostAndPort("10.10.1.146",7005));
        nodes.add(new HostAndPort("10.10.1.146",7006));

        JedisCluster jedisCluster = new JedisCluster(nodes);
        jedisCluster.set("key1","redis cluster");
        String str = jedisCluster.get("key1");
        System.out.println(str);
        jedisCluster.close();
    }

3、jedis整合spring(单机版)

    <!--redis连接池配置-->
    <bean name="redisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大连接数 -->
        <property name="maxTotal" value="30" />
        <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="10" />
        <!-- 每次释放连接的最大数目 -->
        <property name="numTestsPerEvictionRun" value="1024" />
        <!-- 释放连接的扫描间隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="30000" />
        <!-- 连接最小空闲时间 -->
        <property name="minEvictableIdleTimeMillis" value="1800000" />
        <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
        <property name="softMinEvictableIdleTimeMillis" value="10000" />
        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
        <property name="maxWaitMillis" value="1500" />
        <!-- 在获取连接的时候检查有效性, 默认false -->
        <property name="testOnBorrow" value="true" />
        <!-- 在空闲时检查有效性, 默认false -->
        <property name="testWhileIdle" value="true" />
        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
        <property name="blockWhenExhausted" value="false" />
    </bean>

    <!--redis单机版配置-->
    <bean id="redisClient" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="host" value="10.10.1.146"></constructor-arg>
        <constructor-arg name="port" value="6379"></constructor-arg>
        <constructor-arg name="poolConfig" ref="redisPoolConfig"></constructor-arg>
    </bean>
    /**
     * redis整合spring单机版测试
     */
    @Test
    public void testSpringJedisSingle(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
        JedisPool pool = (JedisPool) applicationContext.getBean("redisClient");
        Jedis jedis = pool.getResource();
        String name = jedis.get("name");
        System.out.println(name);
        jedis.close();
        pool.close();
    }

4、jedis整合spring(集群版)

    <!--redis连接池配置-->
    <bean name="redisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大连接数 -->
        <property name="maxTotal" value="30" />
        <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="10" />
        <!-- 每次释放连接的最大数目 -->
        <property name="numTestsPerEvictionRun" value="1024" />
        <!-- 释放连接的扫描间隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="30000" />
        <!-- 连接最小空闲时间 -->
        <property name="minEvictableIdleTimeMillis" value="1800000" />
        <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
        <property name="softMinEvictableIdleTimeMillis" value="10000" />
        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
        <property name="maxWaitMillis" value="1500" />
        <!-- 在获取连接的时候检查有效性, 默认false -->
        <property name="testOnBorrow" value="true" />
        <!-- 在空闲时检查有效性, 默认false -->
        <property name="testWhileIdle" value="true" />
        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
        <property name="blockWhenExhausted" value="false" />
    </bean>

    <!--redis集群版配置-->
    <bean name="redisClient" class="redis.clients.jedis.JedisCluster">
        <constructor-arg name="nodes">
            <set>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host" value="10.10.1.146"></constructor-arg>
                    <constructor-arg name="port" value="7001"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host" value="10.10.1.146"></constructor-arg>
                    <constructor-arg name="port" value="7002"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host" value="10.10.1.146"></constructor-arg>
                    <constructor-arg name="port" value="7003"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host" value="10.10.1.146"></constructor-arg>
                    <constructor-arg name="port" value="7004"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host" value="10.10.1.146"></constructor-arg>
                    <constructor-arg name="port" value="7005"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg name="host" value="10.10.1.146"></constructor-arg>
                    <constructor-arg name="port" value="7006"></constructor-arg>
                </bean>
            </set>
        </constructor-arg>
        <constructor-arg name="poolConfig" ref="redisPoolConfig"></constructor-arg>
    </bean>
    /**
     * redis整合spring集群版测试
     */
    @Test
    public void testSpringJedisCluster(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
        JedisCluster jedisCluster = (JedisCluster) applicationContext.getBean("redisClient");
        String str = jedisCluster.get("key1");
        System.out.println(str);
        jedisCluster.close();
    }

6、把缓存添加到业务逻辑(把业务逻辑查询到的数据放入redis数据库)

注意:缓存的添加不能影响正常的业务逻辑。

    public List<TbContent> getContentList(long contentCid) {
        //从缓存中取内容
        try {
            String result = jedisClient.hget(INDEX_CONTENT_REDIS_KEY, contentCid + "");
            if (!StringUtils.isBlank(result)) {
                //把字符串转换成list
                List<TbContent> resultList = JsonUtils.jsonToList(result, TbContent.class);
                return resultList;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        //业务逻辑:根据内容分类id在mysql数据库中查询内容列表
        TbContentExample example = new TbContentExample();
        Criteria criteria = example.createCriteria();
        criteria.andCategoryIdEqualTo(contentCid);
        List<TbContent> list = contentMapper.selectByExample(example);
        
        //向缓存中添加内容
        try {
            //把list转换成字符串
            String cacheString = JsonUtils.objectToJson(list);
            jedisClient.hset(INDEX_CONTENT_REDIS_KEY, contentCid + "", cacheString);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return list;
    }

7、缓存同步

解决方案:在taotao-rest工程中发布一个服务。当后台管理系统修改内容后,调用此服务,同步缓存。
当后台管理系统,修改内容之后需要通知redis把修改的内容对应的分类id的key删除。
Service层:

public class RedisServiceImpl implements RedisService {

    @Autowired
    private JedisClient jedisClient;
    
    @Value("${INDEX_CONTENT_REDIS_KEY}")
    private String INDEX_CONTENT_REDIS_KEY;
    
    public TaotaoResult syncContent(long contentCid) {
        try {
            jedisClient.hdel(INDEX_CONTENT_REDIS_KEY, contentCid + "");
        } catch (Exception e) {
            e.printStackTrace();
            return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }
        return TaotaoResult.ok();
    }
}

Controller层:

@Controller
@RequestMapping("/cache/sync")
public class RedisController {

    @Autowired
    private RedisService redisService;
    
    @RequestMapping("/content/{contentCid}")
    public TaotaoResult contentCacheSync(@PathVariable Long contentCid) {
        TaotaoResult result = redisService.syncContent(contentCid);
        return result;
    }
}

同步缓存服务的调用(使用HttpClient调用http://localhost:8080//cache/sync/content/{contentCid}):

image.png
上一篇 下一篇

猜你喜欢

热点阅读