Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
redis优势
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
select 0~15 指定数据库
redis keys命令:
redis字符串命令:
Redis hash : Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
Redis hash 命令:
HSET key field value – 将哈希表 key 中的字段 field 的值设为 value 。
HSETNX key field value – 只有在字段 field 不存在时,设置哈希表字段的值。
HMSET key field1 value1 [field2 value2 ] – 同时将多个 field-value (域-值)对设置到哈希表 key 中。
HDEL key field1 [field2] – 删除一个或多个哈希表字段。
HEXISTS key field – 查看哈希表 key 中,指定的字段是否存在。
HGET key field – 获取存储在哈希表中指定字段的值。
HGETALL key – 获取在哈希表中指定 key 的所有字段和值。
HKEYS key – 获取所有哈希表中的字段。
HMGET key field1 [field2] – 获取所有给定字段的值。
HLEN key – 获取哈希表中字段的数量。
Redis 列表(List): Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
Redis 列表命令
Redis 集合(Set):Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
redis集合命令
Redis 有序集合(sorted set):Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
Redis 有序集合命令:
flushdb 删除当前选择的数据库中所有的key
flushall 删除所有数据库中的所有key
Redis HyperLogLog: Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
什么是基数:比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
Redis HyperLogLog 命令:
Redis 发布订阅:Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道。
Redis 发布订阅命令:
Redis 事务: MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令。将多个命令请求打包,然后一次性、按顺序去执行,在事物执行期间服务器不会终端事物而改去执行其他客户端请求命令,要等事物中的所有命令执行完毕,才去执行其他客户端的请求命令。
在开启事物之前先锁定值,当值发生变化的时候,后续的事物将会提交失败
watch ticket
MULTI
decrby ticket 1
…
EXEC
Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:
一个事务从开始到执行会经历以下三个阶段:
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
Redis 事务命令
Redis 连接:Redis 连接命令主要是用于连接 redis 服务
Redis 连接命令
Redis 数据备份: SAVE 命令用于创建当前数据库的备份,该命令将在 redis 安装目录中创建dump.rdb文件。
Redis 数据恢复:如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG 命令,如下所示:
CONFIG GET dir
以上命令 CONFIG GET dir 输出的 redis 安装目录为 /usr/local/redis/bin
创建 redis 备份文件也可以使用命令 BGSAVE,该命令在后台执行
Redis 安全:我们可以通过 redis 的配置文件设置密码参数,这样客户端连接到 redis 服务就需要密码验证,这样可以让你的 redis 服务更安全。
Redis 管道技术: Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这意味着通常情况下一个请求会遵循以下步骤:
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
持久化: RDB和AOF
RDB(快照): 相当于定期给内存中的数据拍一张照片,保存到硬盘中。
RDB文件的创建,可通过save或者bgsave
自动间隔性保存,可通过以下配置完成:
在满足以下3个条件时,bgsave命令就会被执行,生成dump.rdb文件:
save 900 #900秒内,如果有一个key的value发生变化,则执行RDB
save 300 #300秒内,如果有10个key的value发生变化,则执行RDB
save 60 #60秒内,如果有10000个key的value发生变化,则执行RDB
缺点:在两次RDB之间,数据肯定会丢失。
RDB默认开启,可以在redis.conf配置文件中修改上述策略
save 900 1
save 300 10
save 60 10000
AOF(日志),默认关闭需修改配置文件redis.conf开启,对服务器压力比较大:
appendonly yes 开启AOF
appendfilename “appendonly.aof” AOF产生的日志文件
AOF产生的策略
appendfsync always 每个操作
appendfsync everysec 每秒
appendfsync no
AOF日志的重写,当AOF超过64M时,发生重写。
Redis读写分离,在Redis中可以通过slaveof命令或设置conf配置文件中的slaveof选项,实现主从复制,读写分离。
体系结构和原理
星型结构
优点:效率高
缺点:HA实现麻烦
1)选举其中的一个从节点为Master
2) 其他从节点需要重新连接到新的Master
线型结构
优点:HA实现简单
1)把紧邻的Slave变为Master
缺点:
效率低:
星型结构的实现方式
在主节点的配置文件上面关闭RDB和AOF
bind 0.0.0.0
# save 900 1
# save 300 10
# save 60 10000
appendonly no
修改从节点1的配置文件
bind 0.0.0.0
port 6380
replicaof 192.168.18.177 6379
dbfilename dump_6380.rdb
appendfilename "appendonly_6380.aof"
修改从节点2的配置文件
bind 0.0.0.0
port 6381
replicaof 192.168.18.177 6379
dbfilename dump_6381.rdb
appendfilename "appendonly_6381.aof"
连接指定端口号的redis: redis-cli -p 6379
只能在主节点上面写入数据,不能再从节点上面写入数据,报错信息为
(error) READONLY You can't write against a read only replica.
哨兵机制
Sentinel: (哨岗、哨兵)是Redis高可用解决方案,由一个或多个Sentinel组成,在redis中要实现哨兵机制,redis必须在2.4+版本。
Sentinel哨兵 —> 主服务器下线 ----> 故障迁移(重新选取主服务器) ----> 原主服务器启动后将降级为从服务器
哨兵机制会监视redis集群中的所有节点,当检测到主服务器下线时,哨兵会在所有的从节点中重新选取一个主节点,原主服务器恢复后,将降级为从服务器,并从新的主节点上面复制数据。
哨兵配置,修改sentinel.conf
sentinel monitor mymaster 192.168.18.177 6379 1 #主节点ip 主节点端口号 哨兵个数
sentinel auth-pass # 设置哨兵连接主节点时的用户名和密码
sentinel down-after-milliseconds mymaster 30000 #多少秒内没有收到主节点的心跳,哨兵就认为主节点挂了
sentinel parallel-syncs mymaster 1 #选举新的主节点后,可以同时连接其他从节点个数,不能太大
sentinel failover-timeout mymaster 180000 #失败切换时,允许的最大时间
启动哨兵
redis-sentinel sentinel.conf
启动后日志为
1538:X 15 May 2019 15:45:17.882 # +monitor master mymaster 192.168.18.177 6379 quorum 1
1538:X 15 May 2019 15:45:17.883 * +slave slave 192.168.18.177:6380 192.168.18.177 6380 @ mymaster 192.168.18.177 6379
1538:X 15 May 2019 15:45:17.884 * +slave slave 192.168.18.177:6381 192.168.18.177 6381 @ mymaster 192.168.18.177 6379
查看节点信息: info replication
主节点:
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.18.177,port=6380,state=online,offset=57336,lag=1
slave1:ip=192.168.18.177,port=6381,state=online,offset=57336,lag=1
master_replid:a317eba3b8ffa1ada4d8ae59e7291a00c945d1b9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:57336
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:57336
从节点:
# Replication
role:slave
master_host:192.168.18.177
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:48002
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a317eba3b8ffa1ada4d8ae59e7291a00c945d1b9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:48002
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:48002
Spring Boot连接哨兵的配置文件
spring:
redis:
# host: 192.168.18.177 #连接单节点redis
# password: jfpt_common
# port: 6381
database: 0 #数据库0
timeout: 5000
sentinel: #Redis哨兵(HA)
master: mymaster
nodes: 192.168.18.177:26379
jedis:
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -1
Spring Boot使用redis集群的代码
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("set")
public String setValue(String key, String value){
stringRedisTemplate.opsForValue().set(key, value);
String newValue = stringRedisTemplate.opsForValue().get(key);
return newValue;
}
Redis集群:Redis集群是Redis3.0版本开始提供的分布式数据库方案,通过分片(sharding)进行数据共享,并提供复制和故障迁移的功能,集群中可以有多个master。
槽指派:Redis集群通过分片的方式来保存数据库中的键值,集群中的整个redis数据库别分为16384个槽(slot),数据库中的每个键都数据16384个槽中的其中一个,集群中的每个节点可处理为16384个槽。将Key值进行CRC16计算,得到的数值对16384取模
Redis集群的配置
复制一个全新的redis.conf配置文件
新建cluster 文件夹: mkdir cluster
在cluster下新建文件夹: mkdir -p 7001 7002 7003 7004 7005 7006
修改配置文件
port 7001 # 节点端口号
daemonize yes #
bind 0.0.0.0 #绑定机器IP
dir /usr/redis/cluster/7001/ #数据文件存放位置
pidfile /var/run/redis_7001.pid #7001要和port对应
cluster-enabled yes #启动集群模式
cluster-config-file nodes-7001.conf #7001要和port对应
cluster-node-timeout 10000 #拦截超时等待时间
appendonly yes
appendfilename "appendonly_7001.aof"
将上面的文件分别复制到 cluster/7001 到 cluster/7006,并将使用对应的文件夹的数字替换配置文件中的内容:
:%s /7001/7002
分别启动六个redis服务
redis-server ./cluster/7001/redis.conf
此时往redis中写入数据时会报如下的错误,原因是没有安装ruby
(error) CLUSTERDOWN Hash slot not served
安装ruby
yum install ruby
yum install rubygems
gem install redis
执行上面第三步时会报如下的错误
ERROR: Error installing redis:
redis requires Ruby version >= 2.2.2.
继续执行下面的命令
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
find / -name rvm -print
source /usr/local/rvm/scripts/rvm
rvm list known
rvm install 2.4.1
rvm use 2.4.1
rvm use 2.4.1 --default
rvm remove 2.3.4
ruby --version
gem install redis
链接为:http://www.cnblogs.com/Patrickliu/p/8454579.html
创建集群
./redis-cli --cluster create --cluster-replicas 1 192.168.18.177:7001 192.168.18.177:7002 192.168.18.177:7003 192.168.18.177:7004 192.168.18.177:7005 192.168.18.177:7006
–cluster-replicas 1 表示主从复制比例为1:1,即一个主节点对应一个从节点,在redis集群中默认有16383个solt,默认平均分配
输出的内容为:
M: cbe246e4cb7d2be813e8d75b72ee18f95ce6b1b9 192.168.18.177:7001
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 3e88c6431b67db01a3f37cb73668edd36003b4cf 192.168.18.177:7006
slots: (0 slots) slave
replicates 5515163a16503a5892e0d0fc14a5b292d76216c0
S: 4603f8973e3f641ae839872a5b3e963e19a7de07 192.168.18.177:7005
slots: (0 slots) slave
replicates cbe246e4cb7d2be813e8d75b72ee18f95ce6b1b9
M: 5f45ddefab50f1d57f54ef53d736f1096256449f 192.168.18.177:7003
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 5515163a16503a5892e0d0fc14a5b292d76216c0 192.168.18.177:7002
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 57ef0adbb38bb8caf9616873834dc60d8b2a1d74 192.168.18.177:7004
slots: (0 slots) slave
replicates 5f45ddefab50f1d57f54ef53d736f1096256449f
Can I set the above configuration? (type ‘yes’ to accept): yes
连接验证
redis-cli -c -p 7001
查看集群信息: cluster nodes
57ef0adbb38bb8caf9616873834dc60d8b2a1d74 192.168.18.177:7004@17004 slave 5f45ddefab50f1d57f54ef53d736f1096256449f 0 1558167694000 4 connected
3e88c6431b67db01a3f37cb73668edd36003b4cf 192.168.18.177:7006@17006 slave 5515163a16503a5892e0d0fc14a5b292d76216c0 0 1558167695000 6 connected
4603f8973e3f641ae839872a5b3e963e19a7de07 192.168.18.177:7005@17005 slave cbe246e4cb7d2be813e8d75b72ee18f95ce6b1b9 0 1558167695963 5 connected
cbe246e4cb7d2be813e8d75b72ee18f95ce6b1b9 192.168.18.177:7001@17001 master - 0 1558167694000 1 connected 0-5460
5f45ddefab50f1d57f54ef53d736f1096256449f 192.168.18.177:7003@17003 master - 0 1558167693000 3 connected 10923-16383
5515163a16503a5892e0d0fc14a5b292d76216c0 192.168.18.177:7002@17002 myself,master - 0 1558167692000 2 connected 5461-10922
SpringBoot连接redis集群
spring:
redis:
cluster:
nodes:
- 192.168.18.177:7001
- 192.168.18.177:7002
- 192.168.18.177:7003
- 192.168.18.177:7004
- 192.168.18.177:7005
- 192.168.18.177:7006
jedis:
pool:
max-idle: 100
min-idle: 1
max-active: 1000
max-wait: -1
分布式锁的实现方式
为了确保分布式锁的可用,至少要确保锁的实现同时满足以下4个条件
分布式锁的简单实现
package com.swkang.springboot.springbootredissentinel.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Service
public class RedisUtil {
@Autowired
private StringRedisTemplate redisTemplate;
private String key = "lock_key";
/**
* 基于Redis实现分布式加锁
* @param waitTime 加锁等待时间
* @param timeOut 锁的保存时间
* @return 返回非空字符串,加锁成功
*/
public String lock(int waitTime, int timeOut){
try {
String uuid = UUID.randomUUID().toString();
Long endTime = System.currentTimeMillis() + waitTime;
while(System.currentTimeMillis() < endTime){
if(redisTemplate.opsForValue().setIfAbsent(key, uuid, timeOut, TimeUnit.SECONDS)){
return uuid;
}
}
}catch (Exception e){
e.printStackTrace();;
}
return null;
}
/**
* 释放锁
* @param uuid
*/
public void unlock(String uuid){
try {
if(redisTemplate.opsForValue().get(key).equals(uuid)){
redisTemplate.delete(key);
}
} catch (Exception e){
e.printStackTrace();
}
}
}