Redis分布式缓存配置和使用

Redis

Redis是一个分布式缓存系统。具有内存缓存和持久化双重功能。可以作为nosql数据库使用。

一、缓存解决的问题

因为频繁的数据库请求,会导致数据库压力过大,并且请求速度较慢(比如:数据库隔离级别为了避免脏读和幻读,会加入读写锁机制,从而导致访问出现延迟等待现象)。总而言之,缓存是为了减轻数据库的压力。

  • 应用场景案例

“点赞”功能是网站非常普遍的一个功能。但是问题出现:点赞需要记录数据,但是点赞的相应速度要非常高,点赞的并发也是非常高的。如何解决这种并发大、响应速度快的需求呢?

二、安装

  • 先安装gcc工具(gcc是linux下的一个编译器,可以用来编译c、c++等代码)
yum -y install gcc //-y表示自动安装
  • 安装Redis
wget http://download.redis.io/releases/redis-2.8.17.tar.gz //下载redis安装包
tar xzf redis-2.8.17.tar.gz
cd redis-2.8.17
make
  • BUG
使用 make MALLOC=libc 进行编译。MALLOC表示C语言中的动态分配内存函数,libc就是库文件

三、启动

  • 启动服务器
src/redis-server
  • 启动客户端
src/redis-cli
  • 测试
[javen@localhost src]$ ./redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> ping ok
"ok"
127.0.0.1:6379> set name "zhangsan" EX 10 //EX 10表示10秒后过期
OK
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> get name
(nil)

//数据库1000万数据量,Redis中存储了20万的数据,怎么保证20万全是热点数据?

四、使用

既然Redis是缓存,那么它的作用呢,就只有存储数据和获取数据

4.1、存储字符串

set key value
get key

4.2、存储Hash值

hash存储,一般可以用来存储Java中的一个完整的自定义对象(比如dto)。

//hmset是存储hash值的指令,
//user是当前hash的key
//name "zhangsan" age 23 sex "nan" 是 key对应的值
127.0.0.1:6379> hmset user name "zhangsan" age 23 sex "nan"
OK
//hmget获取hash中的某一个属性的值
127.0.0.1:6379> hmget user name
1) "zhangsan"
127.0.0.1:6379> hmget user age
1) "23"
//hgetall是获取hash中的所有属性对应的值
127.0.0.1:6379> hgetall user
1) "name"
2) "zhangsan"
3) "age"
4) "23"
5) "sex"
6) "nan"

4.3、存储List列表(有序列表)

//lpush用来存储一个列表的命令。interesting是列表的名称,"basketball"列表中的值
127.0.0.1:6379> lpush interesting "basketball"
(integer) 1
127.0.0.1:6379> lpush interesting "football" "ball"
(integer) 3
//lrange输出列表中的数据的命令, interesting就是列表的名称 。 0 2是列表的开始输出索引和结束索引。
127.0.0.1:6379> lrange interesting 0 2
1) "ball"
2) "football"
3) "basketball"

4.4、存储Set集合(无序集合)

sadd key member //存数据
smembers key //取数据

案例:
127.0.0.1:6379> sadd strset "a" "b" "c"
(integer) 3
127.0.0.1:6379> smembers strset
1) "b"
2) "c"
3) "a"

4.5、存储zset集合(有序集合)

zadd key score member  (score是一个数字,zset就是通过这个数字进行排序,可以重复)
ZRANGEBYSCORE key 0 1000 //通过分数排序输出

注意:存入set集合中的数据是唯一的。有序集合,如果存入重复数据,则后一个数据的score会覆盖原有数据的score。

五、发布订阅者模式

两个客户端,一个是发布者、另一个是订阅者。发布者发布的消息,订阅者能收到。
SUBSCRIBE java  //订阅Java频道的消息
publish Java “消息” //向Java频道发送消息

六、事务

Redis中的事务具备隔离性和原子性。

隔离性:一个事务在执行过程中不会被其他请求所打断执行。

原子性:要么全部成功、要么全部失败(跟关系型数据的事务原子性有一定理解上的差异。Redis的事务不存在回滚机制,所以这句话跟传统意义的效果有一定的差异)。

multi //开启事务
exec //结束事务

说明:Redis事务是没有事务回滚概念。因为Redis语法简单,不会出现运行异常。即使出现语法异常是不会导致事务回滚。

七、安全配置

 config set requirepass 123456 //配置redis的密码
 config get requirepass //查看密码

 验证密码:auth 123456
 带密码登录:./redis-cli -h 127.0.0.1 -p 6379  -a 123456   // -h表示主机IP,-p端口,-a密码

八、Java操作Redis

  • 准备

    关闭linux服务器的防火墙 
    修改redis的配置redis.conf文件中的bind 127.0.0.1注释掉 
    启动redis: ./src/redis-server redis.conf 
    关闭redis的保护模式:config set protected-mode no  (默认是yes

  • 存字符串

@Test    
public void testCase1(){        
//创建Redis的客户端        
//参数1:IP地址,或者主机名称        
//参数2:端口,redis的默认端口是6379        
Jedis jedis = new Jedis("192.168.72.188",6379);        
//配置登录密码        
jedis.auth("123456");        
//存储字符串        
jedis.set("username","zhangsan");

/取出缓存中数据        
String username = jedis.get("username");        
System.out.println("缓存中的数据:"+username);

    }
  • 存集合
/**
     * 有序set集合
     */
    @Test
    public void testCase3(){
        Jedis jedis = new Jedis("192.168.72.188", 6379);
        jedis.auth("123456");
        //存入有序集合
        //参数1:集合的名称
        //参数2:用来排序的分数,一个整数
        //参数3:集合中值
        jedis.zadd("set",0,"zhangsan");
        jedis.zadd("set",1,"lisi");
        //获取集合中的数据
        Set<String> set = jedis.zrangeByScore("set", 0, 3);
        for (String str:set) {
            System.out.println(str);
        }
    }
  • 连接池
/**
     * Redis的连接池
     */
    @Test
    public void testCase5(){

        //创建连接池的参数对象
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //最大等待时间
        jedisPoolConfig.setMaxWaitMillis(10000);
        //最大休眠时间
        jedisPoolConfig.setMaxIdle(10000);
        //连接池最大连接数
        jedisPoolConfig.setMaxTotal(1000);

        JedisPool jedisPool = new JedisPool(jedisPoolConfig,"192.168.72.188",6379);

        //获取连接
        Jedis jedis = jedisPool.getResource();
        jedis.auth("123456");
        String username = jedis.get("username");
        System.out.println(username);
    }

九、Spring整合Redis

http://projects.spring.io/spring-data-redis/

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.9.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-redis</artifactId>
      <version>1.8.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.3.9.RELEASE</version>
    </dependency>
  • redis配置
 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置连接池参数-->
    <bean id="redisConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxWaitMillis" value="10000"/>
    </bean>
    <!--配置Jedis工厂-->
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="port" value="6379"/>
    <property name="hostName" value="192.168.72.188"/>
    <property name="password" value="123456"/>
    <property name="poolConfig" ref="redisConfig"/>
    </bean>

    <!--配置Jedis模板,用来操作redis api的类-->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
            <property name="connectionFactory" ref="jedisConnectionFactory"/>
    </bean>
    </beans>
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.data.redis.core.ListOperations; 
import org.springframework.data.redis.core.RedisTemplate; 
import org.springframework.data.redis.core.StringRedisTemplate; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.HashMap; 
import java.util.List; 
import java.util.concurrent.TimeUnit;

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:spring-redis.xml") 
public class SpringRedisTest {


    @Autowired    
    private StringRedisTemplate redisTemplate;


    @Test
    public void testCase1(){
    //存储字符串
    //参数1:key
    //参数2:值 value
    //参数3:生命周期
    //参数4:生命周期的时间单位
    //redisTemplate.restore("name33","zhangsanspring".getBytes(),10000, TimeUnit.MILLISECONDS);
    //存储字符串
    redisTemplate.boundValueOps("name33").append("zhangsan");
    }

    /**
    * 存储列表
    */
    @Test
    public void testCase2(){

        //存列表数据
        redisTemplate.boundListOps("list2").leftPushAll("a","b","c","d");

        //获取列表数据
        List<String> list2 = redisTemplate.boundListOps("list2").range(0, 10);
        for (String str : list2) {
            System.out.println(str);
            }
    }

    @Test
    public void testCase3(){
        HashMap<String, String> hashMap = new HashMap<String, String>(); 
        hashMap.put("name","zhangsan"); 
        redisTemplate.boundHashOps("hashdata").putAll(hashMap);
    } }

edis缓存流

十、BUG

redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
 at redis.clients.jedis.Protocol.processError(Protocol.java:127)
 at redis.clients.jedis.Protocol.process(Protocol.java:161)
 at redis.clients.jedis.Protocol.read(Protocol.java:215)
 at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
 解决:
 config set stop-writes-on-bgsave-error no
redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect
 at redis.clients.jedis.Connection.connect(Connection.java:207)
 at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:93)
 at redis.clients.jedis.Connection.sendCommand(Connection.java:126)
 解决:
 将/redis-xxx/redis.conf文件中的bind 127.0.0.1注释掉 
redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
 at redis.clients.jedis.Protocol.processError(Protocol.java:127)
 at redis.clients.jedis.Protocol.process(Protocol.java:161)
 at redis.clients.jedis.Protocol.read(Protocol.java:215)
 at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
 at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:239)
 解决:
 执行命令:config set protected-mode no
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨景文Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值