Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如
下:
字符串类型
散列类型 (对应Java中的Object,它主要用来存储对象)
列表类型 (List)
集合类型 (Set)
有序集合类型。 (TreeSet)
缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)
分布式集群架构中的session分离。
聊天室的在线好友列表。
任务队列。(秒杀、抢购、12306等等)
应用排行榜。
网站访问统计。
数据过期处理(可以精确到毫秒)
su root : 切换到root
1、cd /etc/sysconfig/network-scripts中找到为为ifcfg-eth0的一个。
2、使用命令vim ifcfg-eth0 命令进入到命令行模式下
3、修改相应的ip和修改启动项为yes,按下Esc退到命令行,再按下:wq保存退出
4、service network restart重启网络服务即可。
ifconfig eth0 192.168.125.100
重启网络service network restart
ifup eth0 : 激活连接
1、vim /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
search localdomain
2、然后重启网卡:使用命令: service network restart
redis是C语言开发,建议在linux上运行,示例使用CentOS7作为安装环境。
安装redis需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要安装gcc
yum install gcc-c++
阿里云的CentOS7默认已经内置了gcc,可以跳过这一步
下载redis
从官网下载
http://download.redis.io/releases/redis-5.0.5.tar.gz
将redis-5.0.5.tar.gz拷贝任意路径下,如 /home/john/opt/
解压源码
cd /home/john/opt/
tar -zxvf redis-3.0.0.tar.gz
进入解压后的目录进行编译安装
cd /home/john/opt/redis-5.0.5/src
make # 编译源代码
make install # 安装
# 上面两步也可以直接通过 make && make install两步并一步执行
Redis默认的安装目录是/usr/local/bin, 我们在执行make install命令时添加prefix参数可修改默认安装位置,如: make PREFIX=/usr/local/redis install
redis.conf是redis的配置文件,默认在redis源码包解压后的根目录有一份redis.conf文件,我们可将其拷贝一份到上一步中redis的安装目录
cd /home/john/opt/redis-5.0.5/src
cp redis.conf /usr/local/bin
我们装完redis以后,默认的安装路径是/usr/local/bin,系统会自动来此目录寻找命令,所以我们不需要在配置环境变量,在任意目录都可以使用redis相关的命令,如redis-server、redis-cli
启动命令:
redis-server /usr/local/bin/redis.conf
通过上面的命令启动,redis将以前端模式启动,前端模式启动的缺点是ssh命令窗口关闭则redis-server程序结束,不推荐使用此方法。
放开 # requirepass foobared 这行注释,将后面的foobared改成你自己需要设置的密码
客户端连接时,需要添加-a 参数指定密码才能连上来。
将 # daemonize no 这行放开注释, 并且改成 yes, Redis server将以后台方式运行。
将 logfile “” 改成 logfile “你需要的redis日志文件名称”, 默认的空字符串代表输出到前端控制台(标准输出)
修改redis.conf配置文件, daemonize yes 以后端模式启动。
启动命令和前端启动一样,只不过控制台不会输出任何信息,而且命令结束,如果没有异常会马上退出。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
application.yml
spring:
redis:
host: www.taotao.com
# port: 6379
# password:
jedis:
pool:
max-idle: 2
max-wait: 1000ms
通过创建单实例jedis对象连接redis服务,如下代码:
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestRedisClient {
@Autowired
private StringRedisTemplate redisTemplate;
@Test
public void testRedis() {
Set<String> keys = redisTemplate.keys("*");
log.info("操作前存在的keys: " + keys);
String key = "lanou_F4";
redisTemplate.opsForList().rightPushAll(key, new String[]{"宋超", "国胜", "国伟", "高飞"});
long size = redisTemplate.opsForList().size(key);
log.info("当前"+key+"值的数量: " + size);
List<String> values = redisTemplate.opsForList().range(key, 0, size);
log.info("当前" + key +"的值: " + values);
keys = redisTemplate.keys("*");
log.info("操作后存在的keys: " + keys);
}
}
由于linux防火墙默认开启,redis的服务端口6379并不在开放规则之内,所有需要将此端口开放访问或者关闭防火墙。
关闭防火墙命令:sevice iptables stop
如果是修改防火墙规则,可以修改:/etc/sysconfig/iptables文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6EE61sGR-1592644866491)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image013.jpg)]
架构细节:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m5ZTfRvB-1592644866505)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image014.jpg)]
(1)领着投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.
(2):什么时候整个集群不可用(cluster_state:fail)?
a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态. ps : redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败.
b:如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态.
ps:当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
redis集群管理工具redis-trib.rb依赖ruby环境,首先需要安装ruby环境:
安装ruby
yum install ruby
yum install rubygems
安装ruby和redis的接口程序
拷贝redis-3.0.0.gem至/usr/local下
执行:
gem install /usr/local/redis-3.0.0.gem
这里在同一台服务器用不同的端口表示不同的redis服务器,如下:
主节点:192.168.101.3:7001 192.168.101.3:7002 192.168.101.3:7003
从节点:192.168.101.3:7004 192.168.101.3:7005 192.168.101.3:7006
在/usr/local下创建redis-cluster目录,其下创建7001、7002。。7006目录,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ucNMLpoN-1592644866507)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image016.jpg)]
将redis安装目录bin下的文件拷贝到每个700X目录内,同时将redis源码目录src下的redis-trib.rb拷贝到redis-cluster目录下。
修改每个700X目录下的redis.conf配置文件:
port XXXX
#bind 192.168.101.3
cluster-enabled yes
pidfile /var/run/redis_6379.pid #这里的进程文件也要修改一下,否则会冲突
进入/usr/local/redis_cluster目录下,编写启动集群脚本:start_redis_cluster.sh
cd /usr/local/redis_cluster
vim start_redis_cluster.sh
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SybRp3so-1592644866511)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image018.jpg)]
编辑完成后,按ESC切换到命令模式, 输入ZZ 或者 :wq保存退出。
启动Redis集群中所有节点:
./start_redis_cluster.sh
查看redis进程:
ps aux | grep redis
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N5QC9HeS-1592644866514)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image020.jpg)]
Redis 5以下需要使用redis-trib.rb这个Ruby脚本来管理集群,所以需要事先安装Ruby运行环境
执行redis-trib.rb,此脚本是ruby脚本,它依赖ruby环境。
./redis-trib.rb create --replicas 1 192.168.101.3:7001 192.168.101.3:7002 192.168.101.3:7003 192.168.101.3:7004 192.168.101.3:7005 192.168.101.3:7006
Redis 5开始,集群不需要依赖Ruby,官方直接提供了集群管理支持
注意:如果创建redis集群的时候,ip用的是127.0.0.1,那么你在用Java客户端远程操作Redis集群的时候,会死活连不上,一直是报127.0.0.1:7001无法连接
解决办法:创建Redis集群时,用外部可以访问的IP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bUFt12JY-1592644866516)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image022.jpg)]
说明:
redis集群至少需要3个主节点,每个主节点有一个从节点总共6个节点
–cluster-replicas指定为1表示每个主节点有一个从节点
注意:
如果执行时报如下错误:
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0
解决方法是删除生成的配置文件nodes.conf,如果不行则说明现在创建的结点包括了旧集群的结点信息,需要删除redis的持久化文件后再重启redis,比如:appendonly.aof、dump.rdb
创建集群输出如下:
>>> Creating cluster
Connecting to node 192.168.101.3:7001: OK
Connecting to node 192.168.101.3:7002: OK
Connecting to node 192.168.101.3:7003: OK
Connecting to node 192.168.101.3:7004: OK
Connecting to node 192.168.101.3:7005: OK
Connecting to node 192.168.101.3:7006: OK
>>> Performing hash slots allocation on 6 nodes…
Using 3 masters:
192.168.101.3:7001
192.168.101.3:7002
192.168.101.3:7003
Adding replica 192.168.101.3:7004 to 192.168.101.3:7001
Adding replica 192.168.101.3:7005 to 192.168.101.3:7002
Adding replica 192.168.101.3:7006 to 192.168.101.3:7003
M: cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 192.168.101.3:7001
slots:0-5460 (5461 slots) master
M: 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841 192.168.101.3:7002
slots:5461-10922 (5462 slots) master
M: 1a8420896c3ff60b70c716e8480de8e50749ee65 192.168.101.3:7003
slots:10923-16383 (5461 slots) master
S: 69d94b4963fd94f315fba2b9f12fae1278184fe8 192.168.101.3:7004
replicates cad9f7413ec6842c971dbcc2c48b4ca959eb5db4
S: d2421a820cc23e17a01b597866fd0f750b698ac5 192.168.101.3:7005
replicates 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841
S: 444e7bedbdfa40714ee55cd3086b8f0d5511fe54 192.168.101.3:7006
replicates 1a8420896c3ff60b70c716e8480de8e50749ee65
Can I set the above configuration? (type ‘yes’ to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join…
>>> Performing Cluster Check (using node 192.168.101.3:7001)
M: cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 192.168.101.3:7001
slots:0-5460 (5461 slots) master
M: 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841 192.168.101.3:7002
slots:5461-10922 (5462 slots) master
M: 1a8420896c3ff60b70c716e8480de8e50749ee65 192.168.101.3:7003
slots:10923-16383 (5461 slots) master
M: 69d94b4963fd94f315fba2b9f12fae1278184fe8 192.168.101.3:7004
slots: (0 slots) master
replicates cad9f7413ec6842c971dbcc2c48b4ca959eb5db4
M: d2421a820cc23e17a01b597866fd0f750b698ac5 192.168.101.3:7005
slots: (0 slots) master
replicates 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841
M: 444e7bedbdfa40714ee55cd3086b8f0d5511fe54 192.168.101.3:7006
slots: (0 slots) master
replicates 1a8420896c3ff60b70c716e8480de8e50749ee65
[OK] All nodes agree about slots configuration.
>>> Check for open slots…
>>> Check slots coverage…
[OK] All 16384 slots covered.
在/usr/local/redis_cluster目录下,创建脚本文件:stop_redis_cluster.sh
输入一下内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hKsTTjde-1592644866519)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image024.jpg)]
集群创建成功登陆任意redis结点查询集群中的节点情况。
客户端以集群方式登陆:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VmhfLPIk-1592644866521)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image026.jpg)]
说明:
./redis-cli -c -h 192.168.101.3 -p 7001 ,其中-c表示以集群方式连接redis,-h指定ip地址,-p****指定端口号
cluster nodes 查询集群结点信息
cluster info 查询集群状态信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4c5R7ZlA-1592644866523)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image028.jpg)]
集群创建成功后可以向集群中添加节点,下面是添加一个master主节点
添加7007结点,参考集群结点规划章节添加一个“7007”目录作为新节点。
执行下边命令:
./redis-trib.rb add-node 192.168.101.3:7007 192.168.101.3:7001
Redis 5 添加主节点命令:
语法:redis-cli –cluster add-node **要添加节点的ip:端口 集群中当前存在的任何一个节点的ip**和端口
redis-cli --cluster add-node 10.10.14.166:7006 10.10.14.166:7000
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lJXMX1ML-1592644866525)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image030.jpg)]
查看集群结点发现7007已添加到集群中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lt6PSy3z-1592644866527)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image032.jpg)]
添加完主节点需要对主节点进行hash槽分配这样该主节才可以存储数据。
redis集群有16384个槽,集群中的每个结点分配自已槽,通过查看集群结点可以看到槽占用情况。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W8UTvhFa-1592644866530)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image034.gif)]
给刚添加的7007结点分配槽:
第一步:连接上集群
./redis-trib.rb reshard 192.168.101.3:7001(连接集群中任意一个可用结点都行)
第二步:输入要分配的槽数量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tQ89M5bF-1592644866532)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image036.jpg)]
输入 500表示要分配500个槽
第三步:输入接收槽的结点id
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uJExelRa-1592644866533)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image038.gif)]
这里准备给7007分配槽,通过cluster nodes查看7007结点id为15b809eadae88955e36bcdbb8144f61bbbaf38fb
输入:15b809eadae88955e36bcdbb8144f61bbbaf38fb
第四步:输入源结点id
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vkXg4drK-1592644866535)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image040.gif)]
这里输入all
第五步:输入yes开始移动槽到目标结点id
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3qFEe4IR-1592644866537)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image042.jpg)]
关于Redis 集群的hash slots相关知识,可以参阅:
redis hash slot(虚拟桶)
Redis Cluster及hash slot 算法
集群创建成功后可以向集群中添加节点,下面是添加一个slave从节点。
添加7008从结点,将7008作为7007****的从结点。
./redis-trib.rb add-node --slave --master-id 主节点id 添加节点的ip****和端口 集群中已存在节点ip****和端口
Redis 5 命令:
语法:redis-cli –cluster add-node 要添加节点的ip:端口 **集群中已有master的ip**和端口 --cluster-slave
示例:redis-cli --cluster add-node 10.10.14.166:7006 10.10.14.166:7001 --cluster-slave
执行如下命令:
./redis-trib.rb add-node --slave --master-id cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 192.168.101.3:7008 192.168.101.3:7001
cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 是7007结点的id,可通过cluster nodes查看。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5CmQfpa-1592644866539)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image044.jpg)]
注意:如果原来该结点在集群中的配置信息已经生成cluster-config-file指定的配置文件中(如果cluster-config-file没有指定则默认为nodes.conf),这时可能会报错:
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0
解决方法是删除生成的配置文件nodes.conf,删除后再执行**./redis-trib.rb add-node**指令
查看集群中的结点,刚添加的7008为7007的从节点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NBI7Xgfg-1592644866541)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image046.jpg)]
./redis-trib.rb del-node 127.0.0.1:7005 4b45eb75c8b428fbd77ab979b85080146a9bc017
Redis5以后命令:
redis-cli --cluster del-node ip:port node_id
比如:./redis-cli --cluster del-node 10.10.14.166:7006 d3b977fd46386db84fd85b9240deb602087c8617
删除已经占有hash槽的结点会失败,报错如下:
[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.
需要将该结点占用的hash槽分配出去(参考hash槽重新分配章节)。
配置文件:application.yml
spring:
redis:
host: www.taotao.com
# port: 6379
# password:
jedis:
pool:
max-idle: 2
max-wait: 1000ms
cluster:
nodes: 10.10.14.166:7001,10.10.14.166:7002,10.10.14.166:7003,10.10.14.166:7004,10.10.14.166:7005,10.10.14.166:7006
测试代码
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestRedisClient {
@Autowired
private StringRedisTemplate redisTemplate;
@Test
public void testRedis() {
Set<String> keys = redisTemplate.keys("*");
log.info("操作前存在的keys: " + keys);
String key = "lanou_F4";
redisTemplate.opsForList().rightPushAll(key, new String[]{"宋超", "国胜", "国伟", "高飞"});
long size = redisTemplate.opsForList().size(key);
log.info("当前"+key+"值的数量: " + size);
List<String> values = redisTemplate.opsForList().range(key, 0, size);
log.info("当前" + key +"的值: " + values);
keys = redisTemplate.keys("*");
log.info("操作后存在的keys: " + keys);
}
}
添加缓存逻辑的原则:缓存逻辑不能影响正常的业务逻辑执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s6vcAY5u-1592644866543)(file:///C:\Users\John\AppData\Local\Temp\msohtmlclip1\01\clip_image048.gif)]
gRunner.class)
public class TestRedisClient {
@Autowired
private StringRedisTemplate redisTemplate;
@Test
public void testRedis() {
Set keys = redisTemplate.keys("*");
log.info("操作前存在的keys: " + keys);
String key = "lanou_F4";
redisTemplate.opsForList().rightPushAll(key, new String[]{"宋超", "国胜", "国伟", "高飞"});
long size = redisTemplate.opsForList().size(key);
log.info("当前"+key+"值的数量: " + size);
List values = redisTemplate.opsForList().range(key, 0, size);
log.info("当前" + key +"的值: " + values);
keys = redisTemplate.keys("*");
log.info("操作后存在的keys: " + keys);
}
}
# 6. 系统添加缓存逻辑示例
添加缓存逻辑的原则:**缓存逻辑不能影响正常的业务逻辑执行。**
## 6.1. 添加缓存后系统架构
[外链图片转存中...(img-s6vcAY5u-1592644866543)]