【学习】020 Redis

 

 

Java缓存机制

Java中要用到缓存的地方不少,首当其冲的就是持久层缓存,针对持久层谈一下: 
要实现java缓存有不少种方式,最简单的无非就是static HashMap,这个显然是基于内存缓存,一个map就能够搞定引用对象的缓存,最简单也最不实用,首要的问题就是保存对象的有效性以及周期没法控制,这样很容易就致使内存急剧上升,周期没法控制能够采用SoftReference,WeakReference,PhantomReference这三种对象来执行(看了Ibatis的缓存机制才发现JDK竟然还提供了PhantomReference这玩意儿,得恶补基础啊),这三种都是弱引用,区别在于强度不一样,至于弱引用概念我的理解就是对象的生命周期与JVM挂钩,JVM内存不够了就回收,这样能很好的控制OutOfMemoryError 异常。 html

经常使用的有Oscache,Ehcache,Jcache,Jbosscache等等不少java

OsCache与EhCache区别

 ehcache 主要是对数据库访问的缓存,相同的查询语句只需查询一次数据库,从而提升了查询的速度,使用spring的AOP能够很容易实现这一功能。
 oscache 主要是对页面的缓存,能够整页或者指定网页某一部分缓存,同时指定他的过时时间,这样在此时间段里面访问的数据都是同样的。

NoSQL介绍

NoSQL 是 Not Only SQL 的缩写,意即"不只仅是SQL"的意思,泛指非关系型的数据库。强调Key-Value Stores和文档数据库的优势,而不是单纯的反对RDBMS。mysql

NoSQL产品是传统关系型数据库的功能阉割版本,经过减小用不到或不多用的功能,来大幅度提升产品性能linux

NoSQL产品 Redis、mongodb Membase、HBase 程序员

Redis 与Membase区别

Redis支持数据的持久化,能够将数据存放在硬盘上。web

Memcache不支持数据的之久存储。redis

Redis数据类型丰富,支持set liset等类型算法

Memcache支持简单数据类型,须要客户端本身处理复制对象spring

Redis简介

Redis

Redis 是彻底开源免费的,遵照BSD协议,是一个高性能的key-value数据库。sql

Redis 与其余 key - value 缓存产品有如下三个特色:

Redis支持数据的持久化,能够将内存中的数据保存在磁盘中,重启的时候能够再次加载进行使用。

Redis不只仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

Redis支持数据的备份,即master-slave模式的数据备份。

Redis应用场景

   主要可以体现 解决数据库的访问压力。

   例如:短信验证码时间有效期、session共享解决方案

Redis优点

性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。

丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操做。

原子 – Redis的全部操做都是原子性的,同时Redis还支持对几个操做全并后的原子性执行。

丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过时等等特性。

Redis与其余key-value存储有什么不一样?

Redis有着更为复杂的数据结构而且提供对他们的原子性操做,这是一个不一样于其余数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

Redis运行在内存中可是能够持久化到磁盘,因此在对不一样数据集进行高速读写时须要权衡内存,由于数据量不能大于硬件内存。在内存数据库方面的另外一个优势是,相比在磁盘上相同的复杂的数据结构,在内存中操做起来很是简单,这样Redis能够作不少内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,由于他们并不须要进行随机访问。

Redis安装

 windows 安装redis

  新建start.bat 批处理文件、内容: redis-server.exe  redis.windows.conf

  双击start.bat启动

  修改密码 # requirepass foobared  修改成requirepass 123456

  注意:修改密码的时候前面不要加空格

 linux 安装redis

Redis的官方下载网址是:http://redis.io/download  (这里下载的是Linux版的Redis源码包)

Redis服务器端的默认端口是6379

这里以虚拟机中的Linux系统如何安装Redis进行讲解。

 在windows系统中下载好Redis的源码包。

1. 经过WinSCP工具,将Redis的源码包由windows上传到Linux系统的这个目录/opt/redis (即根目录下的lamp文件夹)。

2. 解压缩。           

tar -zxf redis-2.6.17.tar.gz

3. 切换到解压后的目录。

cd redis-2.6.17  ( 通常来讲,解压目录里的INSTALL文件或README文件里写有安装说明,可参考之)

4. 编译。

make

(注意,编译须要C语言编译器gcc的支持,若是没有,须要先安装gcc。可使用rpm -q gcc查看gcc是否安装)

(利用yum在线安装gcc的命令    yum -y install gcc )

(若是编译出错,请使用make clean清除临时文件。以后,找到出错的缘由,解决问题后再来从新安装。 )

5. 进入到src目录。       

cd src

6. 执行安装。

make install

到此就安装完成。可是,因为安装redis的时候,咱们没有选择安装路径,故是默认位置安装。在此,咱们能够将可执行文件和配置文件移动到习惯的目录。

cd /usr/local

mkdir -p /usr/local/redis/bin    

mkdir -p /usr/local/redis/etc

cd /lamp/redis-2.6.17

cp ./redis.conf /usr/local/redis/etc

cd src

cp mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-dump redis-cli redis-server redis-sentinel /usr/local/redis/bin

7.开放linux 6379 端口

1.编辑 /etc/sysconfig/iptables 文件:

vi /etc/sysconfig/iptables

加入内容并保存:

-A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport 6379 -j ACCEPT

2.重启服务:

/etc/init.d/iptables restart

3.查看端口是否开放:

/sbin/iptables -L -n

比较重要的3个可执行文件:

redis-server:Redis服务器程序

redis-cli:Redis客户端程序,它是一个命令行操做工具。也可使用telnet根据其纯文本协议操做。

redis-benchmark:Redis性能测试工具,测试Redis在你的系统及配置下的读写性能。

Redis的启动命令:

/usr/local/redis/bin/redis-server

cd /usr/local/redis/bin

./redis-server /usr/local/redis/etc/redis.conf    为redis-server指定配置文

修改 redis.conf文件

daemonize yes --- 修改成yes  后台启动

requirepass 123456  ----注释取消掉设置帐号密码

ps aux | grep '6379'  --- 查询端口

kill -15 9886 --- 杀死重置

kill -9 9886 --- 强制杀死

service iptables stop 中止防火墙

redis命令链接方式

./redis-cli -h 127.0.0.1 -p 6379 -a "123456"  --- redis 使用帐号密码链接

PING 结果表示成功

中止redis

redis-cli shutdown  或者 kill redis进程的pid

关闭防火墙

service  iptables stop

Redis客户端链接方式

 使用redisclient-win32.x86.1.5

Redis的基本数据类型

字符串类型(String)

redis 127.0.0.1:6379> SET mykey "redis" 
OK 
redis 127.0.0.1:6379> GET mykey 
"redis"

在上面的例子中,SETGET是redis中的命令,而mykey是键的名称。

Redis字符串命令用于管理Redis中的字符串值。如下是使用Redis字符串命令的语法。

redis 127.0.0.1:6379> COMMAND KEY_NAME

示例

redis 127.0.0.1:6379> SET mykey "redis" 
OK 
redis 127.0.0.1:6379> GET mykey 
"redis"

在上面的例子中,SETGET是redis中的命令,而mykey是键的名称。

Redis字符串命令

下表列出了一些用于在Redis中管理字符串的基本命令。

编号

命令

描述说明

1

SET key value

此命令设置指定键的值。

2

GET key

获取指定键的值。

3

GETRANGE key start end

获取存储在键上的字符串的子字符串。

4

GETSET key value

设置键的字符串值并返回其旧值。

5

GETBIT key offset

返回在键处存储的字符串值中偏移处的位值。

6

MGET key1 [key2..]

获取全部给定键的值

7

SETBIT key offset value

存储在键上的字符串值中设置或清除偏移处的位

8

SETEX key seconds value

使用键和到期时间来设置值

9

SETNX key value

设置键的值,仅当键不存在时

10

SETRANGE key offset value

在指定偏移处开始的键处覆盖字符串的一部分

11

STRLEN key

获取存储在键中的值的长度

12

MSET key value [key value …]

为多个键分别设置它们的值

13

MSETNX key value [key value …]

为多个键分别设置它们的值,仅当键不存在时

14

PSETEX key milliseconds value

设置键的值和到期时间(以毫秒为单位)

15

INCR key

将键的整数值增长1

16

INCRBY key increment

将键的整数值按给定的数值增长

17

INCRBYFLOAT key increment

将键的浮点值按给定的数值增长

18

DECR key

将键的整数值减1

19

DECRBY key decrement

按给定数值减小键的整数值

20

APPEND key value

将指定值附加到键

列表类型(List)

Redis列表是简单的字符串列表,按照插入顺序排序。你能够添加一个元素到列表的头部(左边)或者尾部(右边)

一个列表最多能够包含 232 - 1 个元素 (4294967295, 每一个列表超过40亿个元素)。

redis 127.0.0.1:6379> LPUSH runoobkey redis
(integer) 1
redis 127.0.0.1:6379> LPUSH runoobkey mongodb
(integer) 2
redis 127.0.0.1:6379> LPUSH runoobkey mysql
(integer) 3
redis 127.0.0.1:6379> LRANGE runoobkey 0 10

1) "mysql"
2) "mongodb"
3) "redis"

Redis 列表命令

 

下表列出了列表相关的基本命令:

1

BLPOP key1 [key2 ] timeout 
移出并获取列表的第一个元素,若是列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

2

BRPOP key1 [key2 ] timeout 
移出并获取列表的最后一个元素,若是列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

3

BRPOPLPUSH source destination timeout 
从列表中弹出一个值,将弹出的元素插入到另一个列表中并返回它;若是列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

4

LINDEX key index 
经过索引获取列表中的元素

5

LINSERT key BEFORE|AFTER pivot value 
在列表的元素前或者后插入元素

6

LLEN key 
获取列表长度

7

LPOP key 
移出并获取列表的第一个元素

8

LPUSH key value1 [value2] 
将一个或多个值插入到列表头部

9

LPUSHX key value 
将一个值插入到已存在的列表头部

10

LRANGE key start stop 
获取列表指定范围内的元素

11

LREM key count value 
移除列表元素

12

LSET key index value 
经过索引设置列表元素的值

13

LTRIM key start stop 
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间以内的元素都将被删除。

14

RPOP key 
移除并获取列表最后一个元素

15

RPOPLPUSH source destination 
移除列表的最后一个元素,并将该元素添加到另外一个列表并返回

16

RPUSH key value1 [value2] 
在列表中添加一个或多个值

17

RPUSHX key value 
为已存在的列表添加值

Redis 集合(Set)

RedisSetstring类型的无序集合。集合成员是惟一的,这就意味着集合中不能出现重复的数据。

Redis 集合是经过哈希表实现的,因此添加,删除,查找的复杂度都是O(1)

集合中最大的成员数为 232 - 1 (4294967295, 每一个集合可存储40多亿个成员)

 

实例

redis 127.0.0.1:6379> SADD runoobkey redis
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mongodb
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 0
redis 127.0.0.1:6379> SMEMBERS runoobkey

1) "mysql"
2) "mongodb"
3) "redis"

在以上实例中咱们经过 SADD 命令向名为 runoobkey 的集合插入的三个元素。


Redis 集合命令

 

下表列出了 Redis 集合基本命令:

序号

命令及描述

1

SADD key member1 [member2] 
向集合添加一个或多个成员

2

SCARD key 
获取集合的成员数

3

SDIFF key1 [key2] 
返回给定全部集合的差集

4

SDIFFSTORE destination key1 [key2] 
返回给定全部集合的差集并存储在 destination

5

SINTER key1 [key2] 
返回给定全部集合的交集

6

SINTERSTORE destination key1 [key2] 
返回给定全部集合的交集并存储在 destination

7

SISMEMBER key member 
判断 member 元素是不是集合 key 的成员

8

SMEMBERS key 
返回集合中的全部成员

9

SMOVE source destination member 
member 元素从 source 集合移动到 destination 集合

10

SPOP key 
移除并返回集合中的一个随机元素

11

SRANDMEMBER key [count] 
返回集合中一个或多个随机数

12

SREM key member1 [member2] 
移除集合中一个或多个成员

13

SUNION key1 [key2] 
返回全部给定集合的并集

14

SUNIONSTORE destination key1 [key2] 
全部给定集合的并集存储在 destination 集合中

15

SSCAN key cursor [MATCH pattern] [COUNT count] 
迭代集合中的元素

Redis 有序集合(sorted set)

Redis 有序集合和集合同样也是string类型元素的集合,且不容许重复的成员。

不一样的是每一个元素都会关联一个double类型的分数。redis正是经过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是惟一的,但分数(score)却能够重复。

集合是经过哈希表实现的,因此添加,删除,查找的复杂度都是O(1)集合中最大的成员数为 232 - 1 (4294967295, 每一个集合可存储40多亿个成员)

 

实例

redis 127.0.0.1:6379> ZADD runoobkey 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD runoobkey 4 mysql
(integer) 0
redis 127.0.0.1:6379> ZRANGE runoobkey 0 10 WITHSCORES

1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"

在以上实例中咱们经过命令 ZADD  redis 的有序集合中添加了三个值并关联上分数。


Redis 有序集合命令

 

下表列出了 redis 有序集合的基本命令:

序号

命令及描述

1

ZADD key score1 member1 [score2 member2] 
向有序集合添加一个或多个成员,或者更新已存在成员的分数

2

ZCARD key 
获取有序集合的成员数

3

ZCOUNT key min max 
计算在有序集合中指定区间分数的成员数

4

ZINCRBY key increment member 
有序集合中对指定成员的分数加上增量 increment

5

ZINTERSTORE destination numkeys key [key ...] 
计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key

6

ZLEXCOUNT key min max 
在有序集合中计算指定字典区间内成员数量

7

ZRANGE key start stop [WITHSCORES] 
经过索引区间返回有序集合成指定区间内的成员

8

ZRANGEBYLEX key min max [LIMIT offset count] 
经过字典区间返回有序集合的成员

9

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 
经过分数返回有序集合指定区间内的成员

10

ZRANK key member 
返回有序集合中指定成员的索引

11

ZREM key member [member ...] 
移除有序集合中的一个或多个成员

12

ZREMRANGEBYLEX key min max 
移除有序集合中给定的字典区间的全部成员

13

ZREMRANGEBYRANK key start stop 
移除有序集合中给定的排名区间的全部成员

14

ZREMRANGEBYSCORE key min max 
移除有序集合中给定的分数区间的全部成员

15

ZREVRANGE key start stop [WITHSCORES] 
返回有序集中指定区间内的成员,经过索引,分数从高到底

16

ZREVRANGEBYSCORE key max min [WITHSCORES] 
返回有序集中指定分数区间内的成员,分数从高到低排序

17

ZREVRANK key member 
返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序

18

ZSCORE key member 
返回有序集中,成员的分数值

19

ZUNIONSTORE destination numkeys key [key ...] 
计算给定的一个或多个有序集的并集,并存储在新的 key

20

ZSCAN key cursor [MATCH pattern] [COUNT count] 
迭代有序集合中的元素(包括元素成员和元素分值)

Redis 哈希(Hash)

Redis hash 是一个string类型的fieldvalue的映射表,hash特别适合用于存储对象。

Redis 中每一个 hash 能够存储 232 - 1 键值对(40多亿)。

 

实例

127.0.0.1:6379>  HMSET runoobkey name "redis tutorial" 
127.0.0.1:6379>  HGETALL runoobkey
1) "name"
2) "redis tutorial"
3) "description"
4) "redis basic commands for caching"
5) "likes"
6) "20"
7) "visitors"
8) "23000"

hset  key  mapHey MapValue

在以上实例中,咱们设置了 redis 的一些描述信息(name, description, likes, visitors) 到哈希表的 runoobkey 中。


Redis hash 命令

 

下表列出了 redis hash 基本的相关命令:

序号

命令及描述

1

HDEL key field2 [field2] 
删除一个或多个哈希表字段

2

HEXISTS key field 
查看哈希表 key 中,指定的字段是否存在。

3

HGET key field 
获取存储在哈希表中指定字段的值。

4

HGETALL key 
获取在哈希表中指定 key 的全部字段和值

5

HINCRBY key field increment 
为哈希表 key 中的指定字段的整数值加上增量 increment

6

HINCRBYFLOAT key field increment 
为哈希表 key 中的指定字段的浮点数值加上增量 increment

7

HKEYS key 
获取全部哈希表中的字段

8

HLEN key 
获取哈希表中字段的数量

9

HMGET key field1 [field2] 
获取全部给定字段的值

10

HMSET key field1 value1 [field2 value2 ] 
同时将多个 field-value (-)对设置到哈希表 key 中。

11

HSET key field value 
将哈希表 key 中的字段 field 的值设为 value

12

HSETNX key field value 
只有在字段 field 不存在时,设置哈希表字段的值。

13

HVALS key 
获取哈希表中全部值

14

HSCAN key cursor [MATCH pattern] [COUNT count] 
迭代哈希表中的键值对。

Java操做Redis

 

Redis Jedis

package com.hongmoshui.test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;

public class TestRedis
{
    private Jedis jedis;

    @Before
    public void setup()
    {
        // 链接redis服务器,127.0.0.1:6379
        jedis = new Jedis("127.0.0.1", 6379);
        // 权限认证
        jedis.auth("123456");
    }

    /**
     * redis存储字符串
     */
    @Test
    public void testString()
    {
        // -----添加数据----------
        jedis.set("name", "xinxin");// 向key-->name中放入了value-->xinxin
        System.out.println(jedis.get("name"));// 执行结果:xinxin

        jedis.append("name", " is my lover"); // 拼接
        System.out.println(jedis.get("name"));

        jedis.del("name"); // 删除某个键
        System.out.println(jedis.get("name"));
        // 设置多个键值对
        jedis.mset("name", "liuling", "age", "23", "qq", "476777XXX");
        jedis.incr("age"); // 进行加1操做
        System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));

    }

    /**
     * redis操做Map
     */
    @Test
    public void testMap()
    {
        // -----添加数据----------
        Map<String, String> map = new HashMap<String, String>();
        map.put("name", "xinxin");
        map.put("age", "22");
        map.put("qq", "123456");
        jedis.hmset("user", map);
        // 取出user中的name,执行结果:[minxr]-->注意结果是一个泛型的List
        // 第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key能够跟多个,是可变参数
        List<String> rsmap = jedis.hmget("user", "name", "age", "qq");
        System.out.println(rsmap);

        // 删除map中的某个键值
        jedis.hdel("user", "age");
        System.out.println(jedis.hmget("user", "age")); // 由于删除了,因此返回的是null
        System.out.println(jedis.hlen("user")); // 返回key为user的键中存放的值的个数2
        System.out.println(jedis.exists("user"));// 是否存在key为user的记录
                                                 // 返回true
        System.out.println(jedis.hkeys("user"));// 返回map对象中的全部key
        System.out.println(jedis.hvals("user"));// 返回map对象中的全部value

        Iterator<String> iter = jedis.hkeys("user").iterator();
        while (iter.hasNext())
        {
            String key = iter.next();
            System.out.println(key + ":" + jedis.hmget("user", key));
        }
    }

    /**
     * jedis操做List
     */
    @Test
    public void testList()
    {
        // 开始前,先移除全部的内容
        jedis.del("java framework");
        System.out.println(jedis.lrange("java framework", 0, -1));
        // 先向key java framework中存放三条数据
        jedis.lpush("java framework", "spring");
        jedis.lpush("java framework", "struts");
        jedis.lpush("java framework", "hibernate");
        // 再取出全部数据jedis.lrange是按范围取出,
        // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度
        // -1表示取得全部
        System.out.println(jedis.lrange("java framework", 0, -1));

        jedis.del("java framework");
        jedis.rpush("java framework", "spring");
        jedis.rpush("java framework", "struts");
        jedis.rpush("java framework", "hibernate");
        System.out.println(jedis.lrange("java framework", 0, -1));
    }

    /**
     * jedis操做Set
     */
    @Test
    public void testSet()
    {
        // 添加
        jedis.sadd("user", "liuling");
        jedis.sadd("user", "xinxin");
        jedis.sadd("user", "ling");
        jedis.sadd("user", "zhangxinxin");
        jedis.sadd("user", "who");
        // 移除noname
        jedis.srem("user", "who");
        // 获取全部加入的value
        System.out.println(jedis.smembers("user"));
        // 判断who 是不是user集合的元素
        System.out.println(jedis.sismember("user", "who"));
        System.out.println(jedis.srandmember("user"));
        // 返回集合的元素个数
        System.out.println(jedis.scard("user"));
    }

    @Test
    public void test() throws InterruptedException
    {
        // jedis 排序
        // 注意,此处的rpush和lpush是List的操做。是一个双向链表(但从表现来看的)
        jedis.del("a");// 先清除数据,再加入数据进行测试
        jedis.rpush("a", "1");
        jedis.lpush("a", "6");
        jedis.lpush("a", "3");
        jedis.lpush("a", "9");
        System.out.println(jedis.lrange("a", 0, -1));
        // [9,3, 6,1]
        System.out.println(jedis.sort("a"));
        // [1,3,6,9]
        // 输入排序后结果
        System.out.println(jedis.lrange("a", 0, -1));
    }

//    @Test
//    public void testRedisPool()
//    {
//        RedisUtil.getJedis().set("newname", "中文测试");
//        System.out.println(RedisUtil.getJedis().get("newname"));
//    }
}

SpringBoot集成Redis

Maven依赖jar包

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <!-- <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> 
            <version>2.9.0</version> </dependency> -->
    </dependencies>

新增配置文件信息

########################################################
###Redis (RedisConfiguration)
########################################################
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.timeout=5000

Java代码

package com.hongmoshui.service;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Service
public class RedisService
{
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void setObject(String key, Object value)
    {
        this.setObject(key, value, null);
    }

    public void setObject(String key, Object value, Long time)
    {
        if (StringUtils.isEmpty(key) || value == null)
        {
            return;
        }
        if (value instanceof String)
        {
            // 存放string类型
            String stringValue = (String) value;
            if (time == null)
            {
                stringRedisTemplate.opsForValue().set(key, stringValue);
            }
            else
            {
                stringRedisTemplate.opsForValue().set(key, stringValue, time, TimeUnit.SECONDS);
            }

            return;
        }
        if (value instanceof List)
        {
            // 存放list類型
            List<String> listValue = (List<String>) value;
            for (String string : listValue)
            {
                stringRedisTemplate.opsForList().leftPush(key, string);
            }
        }

    }

    public void delKey(String key)
    {
        stringRedisTemplate.delete(key);
    }

    public String getString(String key)
    {
        return stringRedisTemplate.opsForValue().get(key);

    }

}

Redis主从复制

  克隆三台linux虚拟机

克隆虚拟机

生成新的mack地址

主从复制配置

redis主从复制

概述

一、redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库能够进行读写操做,当发生写操做的时候自动将数据同步到从数据库,而从数据库通常是只读的,并接收主数据库同步过来的数据,一个主数据库能够有多个从数据库,而一个从数据库只能有一个主数据库。

二、经过redis的复制功能能够很好的实现数据库的读写分离,提升服务器的负载能力。主数据库主要进行写操做,而从数据库负责读操做。

主从复制过程

主从复制过程:见下图

过程:

1:当一个从数据库启动时,会向主数据库发送sync命令,

2:主数据库接收到sync命令后会开始在后台保存快照(执行rdb操做),并将保存期间接收到的命令缓存起来

3:当快照完成后,redis会将快照文件和全部缓存的命令发送给从数据库。

4:从数据库收到后,会载入快照文件并执行收到的缓存的命令。

修改redis.conf

修改从redis中的 redis.conf文件

slaveof 192.168.33.130 6379  

masterauth 123456--- 主redis服务器配置了密码,则须要配置

Redis哨兵机制

什么是哨兵机制

Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器,该系统执行如下三个任务:

·        监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运做正常。

·        提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 能够经过 API 向管理员或者其余应用程序发送通知。

·        自动故障迁移(Automatic failover):当一个Master不能正常工做时,哨兵(sentinel) 会开始一次自动故障迁移操做,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其余Slave改成复制新的Master; 当客户端试图链接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可使用Master代替失效Master。

哨兵(sentinel) 是一个分布式系统,你能够在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)来接收关于Master是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪一个Slave做为新的Master.

每一个哨兵(sentinel) 会向其它哨兵(sentinel)、master、slave定时发送消息,以确认对方是否”活”着,若是发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的主观认为宕机” Subjective Down,简称sdown).

若“哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master"完全死亡"(:客观上的真正down,Objective Down,简称odown),经过必定的vote算法,从剩下的slave节点中,选一台提高为master,而后自动修改相关配置.

虽然哨兵(sentinel) 释出为一个单独的可执行文件 redis-sentinel ,但实际上它只是一个运行在特殊模式下的 Redis 服务器,你能够在启动一个普通 Redis 服务器时经过给定 --sentinel 选项来启动哨兵(sentinel).

哨兵(sentinel) 的一些设计思路和zookeeper很是相似

单个哨兵(sentinel)

 

哨兵模式修改配置

实现步骤:

1.拷贝到etc目录

cp sentinel.conf  /usr/local/redis/etc

2.修改sentinel.conf配置文件

sentinel monitor mymast  192.168.110.133 6379 1  #主节点 名称 IP 端口号 选举次数

3. 修改心跳检测 5000毫秒

sentinel down-after-milliseconds mymaster 5000

4.sentinel parallel-syncs mymaster 2 --- 作多多少合格节点

5. 启动哨兵模式

./redis-server /usr/local/redis/etc/sentinel.conf --sentinel &

6. 中止哨兵模式

Redis事务

Redis事务

Redis 事务能够一次执行多个命令, 而且带有如下两个重要的保证:

事务是一个单独的隔离操做:事务中的全部命令都会序列化、按顺序地执行。事务在执行的过程当中,不会被其余客户端发送来的命令请求所打断。

事务是一个原子操做:事务中的命令要么所有被执行,要么所有都不执行。

一个事务从开始到执行会经历如下三个阶段:

开始事务。

命令入队。

执行事务。

实例

如下是一个事务的例子, 它先以 MULTI 开始一个事务, 而后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的全部命令:

redis 127.0.0.1:6379> MULTI
OK

redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED

redis 127.0.0.1:6379> GET book-name
QUEUED

redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED

redis 127.0.0.1:6379> SMEMBERS tag
QUEUED

redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
   2) "C++"
   3) "Programming"

Redis 事务命令

下表列出了 redis 事务的相关命 

序号    命令及描述
1      DISCARD #取消事务,放弃执行事务块内的全部命令。
2      EXEC #执行全部事务块内的命令。
3      MULTI #标记一个事务块的开始。
4      UNWATCH #取消 WATCH 命令对全部 key 的监视。
5      WATCH key [key ...] #监视一个(或多个) key ,若是在事务执行以前这个(或这些) key 被其余命令所改动,那么事务将被打断。

Redis持久化

什么是Redis持久化

什么是Redis持久化,就是将内存数据保存到硬盘。

Redis 持久化存储 (AOF 与 RDB 两种模式)

RDB持久化

RDB 是在某个时间 点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
优势:使用单独子进程来进行持久化,主进程不会进行任何 IO 操做,保证了 redis 的高性能
缺点:RDB 是间隔一段时间进行持久化,若是持久化之间 redis 发生故障,会发生数据丢失。因此这种方式更适合数据要求不严谨的时候

这里说的这个执行数据写入到临时文件的时间点是能够经过配置来本身肯定的,经过配置redis n 秒内若是超过 m key 被修改这执行一次 RDB 操做。这个操做就相似于在这个时间点来保存一次 Redis 的全部数据,一次快照数据。全部这个持久化方法也一般叫作 snapshots。

RDB 默认开启,redis.conf 中的具体配置参数以下;

#dbfilename:持久化数据存储在本地的文件
dbfilename dump.rdb
#dir:持久化数据存储在本地的路径,若是是在/redis/redis-3.0.6/src下启动的redis-cli,则数据会存储在当前src目录下
dir ./
##snapshot触发的时机,save    
##以下为900秒后,至少有一个变动操做,才会snapshot  
##对于此值的设置,须要谨慎,评估系统的变动操做密集程度  
##能够经过“save “””来关闭snapshot功能  
#save时间,如下分别表示更改了1个key时间隔900s进行持久化存储;更改了10个key300s进行存储;更改10000个key60s进行存储。
save 900 1
save 300 10
save 60 10000
##当snapshot时出现错误没法继续时,是否阻塞客户端“变动操做”,“错误”可能由于磁盘已满/磁盘故障/OS级别异常等  
stop-writes-on-bgsave-error yes  
##是否启用rdb文件压缩,默认为“yes”,压缩每每意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间  
rdbcompression yes  

AOF持久化

Append-only file,将“操做 + 数据”以格式化指令的方式追加到操做日志文件的尾部,在 append 操做返回后(已经写入到文件或者即将写入),才进行实际的数据变动,“日志文件”保存了历史全部的操做过程;当 server 须要数据恢复时,能够直接 replay 此日志文件,便可还原全部的操做过程。AOF 相对可靠,它和 mysql 中 bin.log、apache.log、zookeeper 中 txn-log 简直殊途同归。AOF 文件内容是字符串,很是容易阅读和解析。
优势:能够保持更高的数据完整性,若是设置追加 file 的时间是 1s,若是 redis 发生故障,最多会丢失 1s 的数据;且若是日志写入不完整支持 redis-check-aof 来进行日志修复;AOF 文件没被 rewrite 以前(文件过大时会对命令进行合并重写),能够删除其中的某些命令(好比误操做的 flushall)。
缺点:AOF 文件比 RDB 文件大,且恢复速度慢。

咱们能够简单的认为 AOF 就是日志文件,此文件只会记录“变动操做”(例如:set/del 等),若是 server 中持续的大量变动操做,将会致使 AOF 文件很是的庞大,意味着 server 失效后,数据恢复的过程将会很长;事实上,一条数据通过屡次变动,将会产生多条 AOF 记录,其实只要保存当前的状态,历史的操做记录是能够抛弃的;由于 AOF 持久化模式还伴生了“AOF rewrite”。
AOF 的特性决定了它相对比较安全,若是你指望数据更少的丢失,那么能够采用 AOF 模式。若是 AOF 文件正在被写入时忽然 server 失效,有可能致使文件的最后一次记录是不完整,你能够经过手工或者程序的方式去检测并修正不完整的记录,以便经过 aof 文件恢复可以正常;同时须要提醒,若是你的 redis 持久化手段中有 aof,那么在 server 故障失效后再次启动前,须要检测 aof 文件的完整性。

AOF 默认关闭,开启方法,修改配置文件 reds.conf:appendonly yes

##此选项为aof功能的开关,默认为“no”,能够经过“yes”来开启aof功能  
##只有在“yes”下,aof重写/文件同步等特性才会生效  
appendonly yes  

##指定aof文件名称  
appendfilename appendonly.aof  

##指定aof操做中文件同步策略,有三个合法值:always everysec no,默认为everysec  
appendfsync everysec  
##在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”  
no-appendfsync-on-rewrite no  

##aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”  
auto-aof-rewrite-min-size 64mb  

##相对于“上一次”rewrite,本次rewrite触发时aof文件应该增加的百分比。  
##每一次rewrite以后,redis都会记录下此时“新aof”文件的大小(例如A),那么当aof文件增加到A*(1 + p)以后  
##触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。  
auto-aof-rewrite-percentage 100  

AOF 是文件操做,对于变动操做比较密集的 server,那么必将形成磁盘 IO 的负荷加剧;此外 linux 对文件操做采起了“延迟写入”手段,即并不是每次 write 操做都会触发实际磁盘操做,而是进入了 buffer 中,当 buffer 数据达到阀值时触发实际写入(也有其余时机),这是 linux 对文件系统的优化,可是这却有可能带来隐患,若是 buffer 没有刷新到磁盘,此时物理机器失效(好比断电),那么有可能致使最后一条或者多条 aof 记录的丢失。经过上述配置文件,能够得知 redis 提供了 3 中 aof 记录同步选项:

always:每一条 aof 记录都当即同步到文件,这是最安全的方式,也觉得更多的磁盘操做和阻塞延迟,是 IO 开支较大。

everysec:每秒同步一次,性能和安全都比较中庸的方式,也是 redis 推荐的方式。若是遇到物理服务器故障,有可能致使最近一秒内 aof 记录丢失(可能为部分丢失)。

no:redis 并不直接调用文件同步,而是交给操做系统来处理,操做系统能够根据 buffer 填充状况 / 通道空闲时间等择机触发同步;这是一种普通的文件操做方式。性能较好,在物理服务器故障时,数据丢失量会因 OS 配置有关。

其实,咱们能够选择的太少,everysec 是最佳的选择。若是你很是在乎每一个数据都极其可靠,建议你选择一款“关系性数据库”吧。
AOF 文件会不断增大,它的大小直接影响“故障恢复”的时间, 并且 AOF 文件中历史操做是能够丢弃的。AOF rewrite 操做就是“压缩”AOF 文件的过程,固然 redis 并无采用“基于原 aof 文件”来重写的方式,而是采起了相似 snapshot 的方式:基于 copy-on-write,全量遍历内存中数据,而后逐个序列到 aof 文件中。所以 AOF rewrite 可以正确反应当前内存数据的状态,这正是咱们所须要的;*rewrite 过程当中,对于新的变动操做将仍然被写入到原 AOF 文件中,同时这些新的变动操做也会被 redis 收集起来(buffer,copy-on-write 方式下,最极端的多是全部的 key 都在此期间被修改,将会耗费 2 倍内存),当内存数据被所有写入到新的 aof 文件以后,收集的新的变动操做也将会一并追加到新的 aof 文件中,此后将会重命名新的 aof 文件为 appendonly.aof, 此后全部的操做都将被写入新的 aof 文件。若是在 rewrite 过程当中,出现故障,将不会影响原 AOF 文件的正常工做,只有当 rewrite 完成以后才会切换文件,由于 rewrite 过程是比较可靠的。*

触发 rewrite 的时机能够经过配置文件来声明,同时 redis 中能够经过 bgrewriteaof 指使人工干预。

redis-cli -h ip -p port bgrewriteaof

由于 rewrite 操做 /aof 记录同步 /snapshot 都消耗磁盘 IO,redis 采起了“schedule”策略:不管是“人工干预”仍是系统触发,snapshot 和 rewrite 须要逐个被执行。

AOF rewrite 过程并不阻塞客户端请求。系统会开启一个子进程来完成。

AOF与RDB区别

OF RDB 各有优缺点,这是有它们各自的特色所决定:

1) AOF 更加安全,能够将数据更加及时的同步到文件中,可是 AOF 须要较多的磁盘 IO 开支,AOF 文件尺寸较大,文件内容恢复数度相对较慢。
*2) snapshot,安全性较差,它是“正常时期”数据备份以及 master-slave 数据同步的最佳手段,文件尺寸较小,恢复数度较快。

能够经过配置文件来指定它们中的一种,或者同时使用它们(不建议同时使用),或者所有禁用,在架构良好的环境中,master 一般使用 AOF,slave 使用 snapshot,主要缘由是 master 须要首先确保数据完整性,它做为数据备份的第一选择;slave 提供只读服务(目前 slave 只能提供读取服务),它的主要目的就是快速响应客户端 read 请求;可是若是你的 redis 运行在网络稳定性差 / 物理环境糟糕状况下,建议你 master 和 slave 均采起 AOF,这个在 master 和 slave 角色切换时,能够减小“人工数据备份”/“人工引导数据恢复”的时间成本;若是你的环境一切很是良好,且服务须要接收密集性的 write 操做,那么建议 master 采起 snapshot,而 slave 采用 AOF。

Redis发布订阅

Redis 发布订阅(pub/sub)是一种消息通讯模式:发送者(pub)发送消息,订阅者(sub)接收消息。

Redis 客户端能够订阅任意数量的频道。

下图展现了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

当有新消息经过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

实例

如下实例演示了发布订阅是如何工做的。在咱们实例中咱们建立了订阅频道名为 redisChat:

redis 127.0.0.1:6379> SUBSCRIBE redisChat

Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1

如今,咱们先从新开启个 redis 客户端,而后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。

redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"

(integer) 1

redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"

(integer) 1

# 订阅者的客户端会显示以下消息
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by runoob.com"
发布订阅命令
下表列出了 redis 发布订阅经常使用命令:

1

PSUBSCRIBE pattern [pattern ...] 
订阅一个或多个符合给定模式的频道。

2

PUBSUB subcommand [argument [argument ...]] 
查看订阅与发布系统状态。

3

PUBLISH channel message 
将信息发送到指定的频道。

4

PUNSUBSCRIBE [pattern [pattern ...]] 
退订全部给定模式的频道。

5

SUBSCRIBE channel [channel ...] 
订阅给定的一个或多个频道的信息。

6

UNSUBSCRIBE [channel [channel ...]] 
指退订给定的频道。

相关文章
相关标签/搜索