文章目录
1.redis介绍
1.1 什么是redis?
-
Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
-
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
-
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
1.2为什么使用redis?(redis能做什么/不能做什么)
Redis和MongoDB是当前使用最广泛的NoSQL,而就Redis技术而言,它的性能十分优越,可以支持每秒十几万此的读/写操作,其性能远超数据库,并且还支持集群、分布式、主从同步等配置,原则上可以无限扩展,让更多的数据存储在内存中,更让人欣慰的是它还支持一定的事务能力,这保证了高并发的场景下数据的安全和一致性
Redis都可以干什么事儿?
(1)缓存。毫无疑问这是Redis当今最为人熟知的使用场景,再提升服务器性能方面非常有效。
(2)排行榜。如果使用传统的关系型数据库来做,非常麻烦,而利用Redis的SortSet数据结构能够非常方便搞定;
(3)计算器/限速器。利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力;
(4)好友关系。利用集合的一些命令,比如求交集、并集、差集等,可以方便搞定一些共同好友、共同爱好之类的功能;
(5)简单消息队列。除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制,比如到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦;
(6)Session共享。以PHP为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论用户落在那台机器上都能够获取到对应的Session信息。
Redis不能干什么事儿?
Redis感觉能干的事情特别多,但它不是万能的,合适的地方用它事半功倍,如果滥用可能导致系统的不稳定、成本增高等问题。
(1)比如,用Redis去保存用户的基本信息,虽然它能够支持持久化,但是它的持久化方案并不能保证数据绝对的落地,并且还可能带来Redis性能下降,因为持久化太过频繁会增大Redis服务的压力。
(2)简单总结就是数据量太大、数据访问频率非常低的业务都不适合使用Redis,数据太大会增加成本,访问频率太低,保存在内存中纯属浪费资源。
选择总需要找个理由
上面说了Redis的一些使用场景,那么这些场景的解决方案也有很多其它选择,比如缓存可以用Memcache,Session共享还能用MySql来实现,消息队列可以用RabbitMQ,我们为什么一定要用Redis呢?
速度快,完全基于内存,使用C语言实现,网络层使用epoll解决高并发问题,单线程模型避免了不必要的上下文切换及竞争条件;
注意:单线程仅仅是说在网络请求这一模块上用一个请求处理客户端的请求,想持久化它就会重开一个线程/进程去进行处理。
丰富的数据类型,Redis有8种数据类型,当然常用的主要是 String、Hash、List、Set、 SortSet 这5种类型,他们都是基于键值的方式组织数据。 每一种数据类型提供了非常丰富的操作命令,可以满足绝大部分需求,如果有特殊需求还能自己通过 lua 脚本自己创建新的命令(具备原子性);
1.3 redis的原子性
原子性(atomicity):一个事务是一个不可分割的最小工作单位,要么都成功要么都失败。
原子操作是指你的一个业务逻辑必须是不可拆分的.比如你给别人转钱,你的账号扣钱,别人的账号增加钱,这个业务逻辑就是原子性的,这个操作就是原子操作,要么都成功要么都失败。
Redis所有单个命令的执行都是原子性的
2.redis主从复制下的多台服务器集群——哨兵机制
实验说明:
角色 | server | ip |
---|---|---|
master | server1 | 172.25.254.131 |
slave | server2 | 172.25.254.132 |
slave | server3 | 172.25.254.133 |
- redis的数据保存在/var/lib/redis/6379/dump.rdb
如果有问题,redis起不来,可以删除这文件再试
redis主从复制的实现(集群方式一)
参考官网:http://www.redis.cn/documentation.html
在server1:
(1)redis的安装:
[root@redis1 redis]# tar zxf redis-5.0.3.tar.gz ##解压获取到的安装包
[root@redis1 redis]# cd redis-5.0.3
[root@redis1 redis-5.0.3]# make
[root@redis1 redis-5.0.3]# make install
[root@redis1 redis]#scp redis-5.0.3 root@172.25.19.132:/root ##将解压目录直接发送给其他两台服务器,更省时
[root@redis1 redis]# scp -r redis-5.0.3 root@172.25.19.133:/root
(2)
初始化:
[root@redis1 redis-5.0.3]# cd utils/
[root@redis1 utils]# ./install_server.sh ##启动脚本,进行初始化,全部选默认
(3)对外开放端口(6379):
[root@redis1 utils]# vim /etc/redis/6379.conf ##在配置文件中修改服务端口
70 bind 0.0.0.0
[root@redis1 utils]# /etc/init.d/redis_6379 restart ##重启服务
[root@redis1 utils]# netstat -antulp ##查看端口是否开起
在server2
(1)安装redis
[root@redis2 redis-5.0.3]# make install
(2)初始化
[root@redis1 redis-5.0.3]# cd utils/
[root@redis1 utils]# ./install_server.sh
(3)开放端口,从配置
[root@redis2 utils]# vim /etc/redis/6379.conf
70 bind 0.0.0.0
1379 slaveof 172.25.19.131 6379 ##表示是主机172.25.19.131的slave
[root@redis2 utils]# /etc/init.d/redis_6379 restart ##重启服务
Stopping ...
Redis stopped
Starting Redis server...
在server3:
(1)安装redis
[root@redis3 redis-5.0.3]# make install
(2)初始化
[root@redis1 redis-5.0.3]# cd utils/
[root@redis3 utils]# ./install_server.sh
(3)开放端口,从配置
[root@redis3 utils]# vim /etc/redis/6379.conf
70 bind 0.0.0.0
1379 slaveof 172.25.19.131 6379
[root@redis3 utils]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
测试:
在server1上:
[root@server1 ~]# redis-cli
127.0.0.1:6379> set name wsp
OK
127.0.0.1:6379> get name
"wsp"
在server2上:
[root@server2 ~]# redis-cli
127.0.0.1:6379> get name
"wsp"
在server1上存入的值,在server2上可以看到,但是在server2上不能写入
[root@server2 ~]# vim /etc/redis/6379.conf
[root@server2 ~]# redis-cli
127.0.0.1:6379> get name
"wsp"
127.0.0.1:6379> set name westos
(error) READONLY You can't write against a read only replica.
哨兵模式(集群方式二)
在server1:
[root@redis1 redis-5.0.3]# cp sentinel.conf /etc/redis/ ##复制配置文件,sentinel哨兵
[root@redis1 redis-5.0.3]# cd /etc/redis/
[root@redis1 redis]# ls
6379.conf sentinel.conf
[root@redis1 redis]# vim sentinel.conf ##编辑哨兵配置文件
17 protected-mode no ##关闭保护模式
84 sentinel monitor mymaster 172.25.19.131 6379 2 ##配置master信息,后面的2表示投票机制,至少有2个节点认为master挂了,才会切换
113 sentinel down-after-milliseconds mymaster 10000 ##实验效果改为10s,表示master挂后10s会切换
启动后配置文件会发生变化,方便起见可以先将配置文件发送给从服务器
[root@redis1 redis]# scp ./sentinel.conf root@172.25.19.132:/etc/redis/
root@172.25.19.132's password:
sentinel.conf 100% 9713 9.5KB/s 00:00
[root@redis1 redis]# scp ./sentinel.conf root@172.25.19.133:/etc/redis/
root@172.25.19.133's password:
sentinel.conf 100% 9713 9.5KB/s 00:00
启动哨兵服务:
[root@redis1 redis]# redis-server /etc/redis/sentinel.conf --sentinel
在server2上:
[root@redis2 redis]# redis-server /etc/redis/sentinel.conf --sentinel ##开启哨兵模式
在server3上:
[root@redis3 redis]# redis-server /etc/redis/sentinel.conf --sentinel ##启动哨兵
测试:
在server1上:
查看哨兵模式是否成功:
[root@redis1 ~]# netstat -antulp ##查看哨兵端口是否开启26379
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:26379 0.0.0.0:* LISTEN 16879/redis-server
主
从节点信息:
[root@redis1 ~]# redis-cli
127.0.0.1:6379> info
# Replication
role:master
connected_slaves:2
slave0:ip=172.25.19.132,port=6379,state=online,offset=95268,lag=0
slave1:ip=172.25.19.133,port=6379,state=online,offset=95133,lag=0
sentinel信息:
[root@redis1 ~]# redis-cli -p 26379
127.0.0.1:26379> info
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=172.25.19.131:6379,slaves=2,sentinels=3
哨兵模式测验:
[root@redis1 ~]# redis-cli
127.0.0.1:6379> SHUTDOWN
(选票)
再次查看可以看到新的master:
[root@redis1 ~]# redis-cli -p 26379
127.0.0.1:26379> info
.
.
.
master0:name=mymaster,status=ok,address=172.25.19.133:6379,slaves=2,sentinels=3
127.0.0.1:26379>
3.redis 单服务器集群的实现(集群方式三)
参考官网: http://www.redis.cn/topics/cluster-tutorial.html
实现配置:
(1)先关闭之前的redis
[root@redis1 ~]# /etc/init.d/redis_6379 stop
(2)创建集群节点目录
[root@redis1 redis]# mkdir /usr/local/rediscluster
[root@redis1 redis]# cd /usr/local/rediscluster/
[root@redis1 rediscluster]# ls
[root@redis1 rediscluster]# pwd
/usr/local/rediscluster
[root@redis1 rediscluster]# mkdir 700{1..6}
[root@redis1 rediscluster]# ls
7001 7002 7003 7004 7005 7006
(3)分别编辑各节点配置文件 (有多少个节点就做多少次,需要注意:节点号与配置文件中的要相同)
[root@redis1 rediscluster]# cd 7001
[root@redis1 7001]# vim redis.cnf
port 7001#节点与端口对应
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
pidfile "/usr/local/rediscluster/7001/redis.pid"
logfile "/usr/local/rediscluster/7001/redis.log"
daemonize yes
dir "/usr/local/rediscluster/7001"
[root@redis1 rediscluster]# redis-server redis.conf
启动:(同理配置7002~7006,并启动)
[root@redis1 7001]# redis-server redis.conf
查看:
ps ax
1332 ? Ssl 0:00 redis-server *:7000 [cluster]
(4)查看集群状态
[root@redis1 7006]# redis-cli -p 7001
127.0.0.1:7001> info
# Replication
role:master
connected_slaves:0 ##值为0,说明集群未开启;当值为1集群激活
(5)构建集群
[root@redis1 7006]# yum install ruby -y ##先前的版本需要rube来构建集群,这里不需要
[root@redis1 bin]# redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006
#--cluster-replicas 1表示为每一个master创建1个slave
(6)查看集群信息
[root@redis1 bin]# redis-cli --cluster info 127.0.0.1:7001##输入其他端口也可以,但是必须输一个端口
127.0.0.1:7001 (123c5935...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7003 (93de84b7...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7002 (f4e847f6...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
[root@redis1 bin]# redis-cli --cluster info 127.0.0.1:7002
127.0.0.1:7002 (f4e847f6...) -> 0 keys | 5462 slots | 1 slaves.
127.0.0.1:7003 (93de84b7...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7001 (123c5935...) -> 0 keys | 5461 slots | 1 slaves.
数据集群测试:
[root@redis1 bin]# redis-cli -c -p 7003
127.0.0.1:7003> set age 18
-> Redirected to slot [741] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get age #在任意节点都可以获取到信息,但是都会跳转到7001
"18"
127.0.0.1:7001> exit
[root@redis1 bin]# redis-cli -c -p 7006
127.0.0.1:7006> get name
-> Redirected to slot [5798] located at 127.0.0.1:7004
"nn"
127.0.0.1:7004> get age
-> Redirected to slot [741] located at 127.0.0.1:7001
"18"
127.0.0.1:7001> SHUTDOWN ##挂掉7001,key还会保存在7004上
not connected> EXIT
[root@redis1 bin]# redis-cli -c -p 7006
127.0.0.1:7006> get name
-> Redirected to slot [5798] located at 127.0.0.1:7004
"nn"
127.0.0.1:7004> get age
-> Redirected to slot [741] located at 127.0.0.1:7006
"18"
127.0.0.1:7006> SHUTDOWN
not connected> exit
[root@redis1 bin]# redis-cli -c -p 7006
Could not connect to Redis at 127.0.0.1:7006: Connection refused
not connected> exit
当多个master被shutdown后,集群失效
[root@redis1 bin]# redis-cli -c -p 7005
127.0.0.1:7005> get name
(error) CLUSTERDOWN The cluster is down
127.0.0.1:7005> get name
补充:redis数据存储
redis数据存储在该路径下,redis数据存储在内存之中,只要主机不关机,数据就一直存在
[root@redis1 7004]# pwd
/usr/local/rediscluster/7004
[root@redis1 7004]# ls
appendonly.aof dump.rdb nodes.conf redis.conf redis.log redis.pid
[root@redis1 7004]# cat appendonly.aof
REDIS0009� redis-ver5.0.3�
�]used-mem€m'�time�D
aof-preamble���H@��A�*2
$6
SELECT
$1
0
*3
$3
set
$4
name
$2
yy
*3
$3
set
$4
name
$2
nn