概述
Redis是开源的,遵守BSD协议,c语言编写的高性能(NOSQL)的key-valus数据库,支持基于内存亦可持久化的日志型
应用场景:缓存、排行榜、计数器、分布式会话、分布式锁、社交网络、最新列表、消息系统
Redis优势:性能极高、高速读写、原子性、丰富的数据类型、丰富的特性
缺点:耗内存、数据直接存储在内存中,只有定期快照才能保存在磁盘中,如果突然断电会导致数据的丢失
部署redis服务
Yum -y install gcc make automake autoconf libtool
Wget http://download.redis.io/releases/redis-5.0.8.tar.gz
Tar -zxvf redis-5.0.8.tar.gz -C /usr/local
Cd /usr/local/redis-5.0.8
Make && make intall
./src/redis-server 启动服务端
./src/redis-cli 启动客户端
Set name 123 设置一个值
Get name 查看一个值
Redis-cli -h ip地址 -p 端口 -a 密码
配置
Vim Redis.conf
Daemonize 修改是否以守护进程启动
Pidfile 指定pid文件
Port 指定监听端口
Bind 绑定的主机地址
Timeout 客户端闲置多长时间关闭连接,0为关闭该功能
Loglevel 指定日志记录级别
Logfile 日志记录方式
Database 设置数据库的数量
Save 指定多长时间内,有多少次更新操作,就将数据保存到文件中
Rdbcompression 指定到本地数据时是否压缩数据
Dbfilename 指定本地数据库文件名
Dir 指定本地数据存放目录
Slaveof 本机为从数据库时,设置连接主库时的IP和端口
Masterauth 设置主库的密码
Requirepass 设置redis的连接密码
Maxclients 同一时间客户端的连接数
Maxmemory 指定内存的最大限制
Appendfilename 指定更新日志文件名
修改了配置文件后:redis-server redis.conf 带配置文件启动
redis内存维护策略
Redis作为优秀的中间缓存件,会产生大量的数据,即使采用了集群动态的缓存数据,也应该及时的对数据进行整理,维持系统性能
1.为数据设置超时时间,默认为用不过期
Ttl 键 -1为永不过期 -2 为已过期 其他为生存时间
Expire 键 时间
2.采用LRU算法动态的将不用的数据删除
在内存中但不使用的数据块叫LRU
Volatile-lru:设定了超时时间的数据中,删除不常用的数据
Allkeys-lru:查看所有的数据把最近不常用的数据删除
自定义配置redis
Vim redis.conf
Daemonize yes
Bind ip
Requirepass
最后带配置文件启动
关闭redis服务:
非正常关闭:断电和杀死进程都会丢失数据
正常关闭:在客户端执行shutdown
Docker部署redis:
拉取镜像->启动redis,docker run -d --name redis-6379 -p 6379:6379 redis --requirepass “123456”->连接redis,docker exec -it redis-6379 redis-cli -h ip -p 端口 -a 123456
常用命令
打印所有变量 Keys *
测试是否存在 exists 变量名
存储 Set 变量名 值
获取 get 变量名
打印指定变量 keys 变量名
设置有效时间 Expire 变量名 时间
查看生存时间 ttl 变量名
查看类型 type 变量名
删除变量 Del 变量名
取消过去时间 persist 变量名
毫秒级时间 PEXPIRE 变量名
切换库 select 数据库编号(0-15)
移动变量 move 变量名 库名
删除内存中的所有数据 flushall
删除当前库中的数据 flushdb
手动保存数据到硬盘 save
关闭redis服务 shutdown
Key的命名规范
不能太长,不要超过1024字节,消耗内存
不能太短,可读性不强
统一命名模式
区分大小写
数据类型
字符串string类型,使用set,setnx命令,get查看key值,getrange查看key值的指定的值,getset有则输出,strlen查看key的长度,incr自增,decr自减,incrby自增指定值,decrby自减指定值
set 变量名 value [ex seconds 秒] [px milliseconds 毫秒] [nx 不存在就赋值|xx 存在就覆盖]
从偏移量开始复写key的特定位的值
setrange 变量名 位置(从0位开始) value
set first “hello world”
setrange first 6 “Redis” //改写为hello Redis
strlen 变量名 统计字串长度
strlen first
存在则追加,不存在则创建key及value,返回key长度
append 变量名 value
append myname jacob
对key所存储字串,设置或清除特定偏移量上的位(bit),value值可以为1或0,offset为0~2^32之间,key不存在,则创建新key
setbit 变量名 位置 value
setbit bit 0 1 //设置bit第0位为1
setbit bit 1 0 //设置bit第1位为0
bitcount 变量名 统计字串中被设置为1的比特位数量
将key中的值减1,key不存在则先初始化为0,再减1
decr 变量名 decr test
将key中的值,减去decrement
decrby 变量名 减少量
set count 100
decrby count 20
返回key存储的字符串值,若key不存在则返回nul
若key的值不是字串,则返回错误,get只能处理字串
get key
返回字串值中的子字串,截取范围为start和end
负数偏移量表示从末尾开始计数,-1表示最后一个字
符,-2表示倒数第二个字符
getrange key start end
set first “hello,the world”
getrange first -5 -1
getrange first 0 4
将key的值加1,如果key不存在,则初始为0后再加1,主要应用为计数器,只能是整数
incr key
set page 20 incr page
将key的值增加increment
incrby key increment
为key中所储存的值加上浮点数增量 increment
incrbyfloat key increment
set num 16.1
incrbyfloat num 1.1
获取一个或多个key的值,空格分隔,具有原子性
mget key [key…]
设置多个key及值,空格分隔,具有原子性
mset key value [key value …]
Hash类型,存储的是对象,hset,hmset,hget,hmget,hgetall,hkeys,hlen,hdel,hincrby,hincrbyfl
At
Redis hash:是一个string类型的field和value的映射表,一个key可对应多个field,一个field对应一个value,将一个对象存储为hash类型,较于每个字段都存储成
string类型更能节省内存。
将hash表中field值设置为value
hset key field value
hset site google ‘www.g.cn’
hset site baidu ‘www.baidu.com’
获取hash表中field的值
hget key filed
hget site google
同时给hash表中的多个field赋值
hmset key field value [field value…]
hmset site google www.g.cn baidu www.baidu.com
返回hash表中多个field的值
hmget key field [field…]
hmget site google baidu
返回hash表中所有field名称
hkeys key
hmset site google www.g.cn baidu www.baidu.com
hkeys site
返回hash表中所有field的值
hgetall key
返回hash表中所有filed的值
hvals key
删除hash表中多个field的值,不存在则忽略
hdel key field [field…]
hdel site google baidu
List列表类型,lpush,rpush,lpushx,rpushx,llen,lindex,lrange,lpop,rpop,blpop,brpop,ltrim,lset
,linsert,rpoplpush,brpoplpush
Redis的list是一个字符队列,先进后出,一个key可以有多个值。
将一个或多个值value插入到列表key的表头,Key不存在,则创建key,已存在的变量以追加输入。
lpush key value [value…]
lpush list a b c //list1值依次为c、b、a
从开始位置读取key的值到stop结束
lrange key start stop
lrange list 0 2 //从0位开始,读到2位为止
lrange list 0 -1 //从开始读到结束为止
lrange list 0 -2 //从开始读到倒数第2位为止
移除并返回列表头元素数据,key不存在则返回nil
lpop key
lpop list //删除表头元素,可以多次执行
返回列表key的长度
llen key
返回列表中第index个值
lindex key index
lindex key 0 ; lindex key 2; lindex key -2
将key中index位置的值修改为value
lset key index value
lset list 3 test //将list中第3个值修改为test
将value插入到key的末尾
rpush key value [value…]
rpush list3 a b c //list3值为a b c
rpush list3 d //末尾插入d
删除并返回key末尾的值
rpop key
rpush list4 a b c //list4值为a b c
rpop list4 //删除末尾的c,并返回删除的值
set集合类型,是string的无序集合,sadd,scard,smembers,sismember,srandmember,srem,spop,smove,sdiff,sdiffstore,sinter,sinterstore,sunion,sunionstore
Zset 无序集合类型,zadd,zcard,zcount,zrank,zrange,zrangebyscore,zrevrange,zrevrangeby,
Del,zrem,zremrangebyrank,zremrangebyscore,zincrby
发布订阅
发布订阅是一种消息通信模式,发布者pub发送消息,订阅者sub接收消息
Subscribe channe1 … 订阅给定的一个或多个频道的信息
Psubscribe patten … 订阅一个或多个给定模式的频道
Publish channel message 将信息发送到指定的频道
Unsubscribe channel … 退订指定的频道
Punsubscribe patten … 退订所有给定模式的频道
应用场景,新闻、微博、公众号、实时聊天、群聊
事务
可以一次执行多条命令,保证所有命令序列化,不能回滚,执行过程中不能被其他命令插入,不许出现加塞行为
Multi 标记一个事务块的开始
具体的命令行
Exec 执行所有事务块内的命令
Descard 取消事务,放弃事务块内的所有命令
Unwatch 取消watch命令对所有key的监视
Watch 监视一个或多个key,如果在事务执行之前这个key被其他命令所改动,那么事务将被打断
如果执行事务中的命令出现了错误,那么出现错误的命令不会被执行,其他正确的命令会执行,且不能回滚,如果是事务命令出现了错误,整个事务将被取消
应用场景,一组命令必须同时都执行,或者都不执行,商品秒杀
持久化
是将内存中的数据写入到磁盘中去,防止服务器宕机导致数据丢失
RDB方式,默认的持久化方式,将内存中的数据以快照的方式写入到二进制文件中,默认为dump.rdb,保存和还原速度快,适合灾难备份,不适用于小内存服务器。服务器正常关机或者满足快照策略时写入磁盘。如果宕机将会丢失最后一次快照后修改的数据
备份数据:
备份dump.rdb 文件到其他位置
cp 数据库目录/dump.rdb 备份目录
拷贝备份文件到数据库目录,重启redis服务
[root@52 6379]# cp dump.rdb /root
192.168.4.52:6352> FLUSHALL
192.168.4.52:6352> keys *
192.168.4.52:6352> SHUTDOWN
[root@52 6379]# rm -rf dump.rdb
[root@52 6379]# cp /root/dump.rdb ./
[root@52 6379]# /etc/init.d/redis_6379 start
192.168.4.52:6352> keys *
AOF方式,会将每一个写命令通过write函数追加到文件appendonly.aof,当redis重启后会通过重新执行文件中保存的写命令在内存中重建整个数据库的内容。但是持久化文件会变得越来越大。
Write:根据条件,将aof_puf中的缓存写入到AOF文件
SAVE:根据条件,调用fsync或fdatasync函数,将AOF文件保存到磁盘中
Appendonly yes 启动aof持久化方式
Appendfsync always 收到命令就立即写入磁盘,最慢,但是保证完全的持久化
Appendfsynceverysec 每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
数据一致性
对一致性要求较高的,应采用实时同步的方案,即查询缓存查询不到在从DB查询,保存到缓存;更新缓存时,先更新数据库,再将缓存的设置过期。
实时,一方修改,另一方同时修改;
非实时,一方修改,另一方不需要同时修改
队列,对于并发程度较高的,可以采用异步队列的方式同步
阿里的同步工具cannal,模拟MySQL的主从同步机制,监控DB bitlog日志更新来触发缓存的更新
Cannl模拟MySQL slave的交互协议,伪装自己为MySQL slave,向MySQL master方式dump协议,MySQL master收到dump请求,开始推送binary log给slave也就是canal,canal解析binary log对象
穿透
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库中去查询,造成缓存穿透。持久层查不到就缓存空结果,查询前先判断缓存中是否exists,如果有直接返回空,没有则查询后返回;insert时需要清楚查询的key,否则即便DB中有也查不到
雪崩
缓存大量失效的时候,引发大量查询数据
可以分析用户行为,尽量让失效时间均匀分布,大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程写,从而避免失效时大量并发请求落到底层存储系统上
热点key
某个key访问非常频繁,当key失效的时候有大量线程来构建缓存,导致负载增加,系统崩溃
主从复制
slave向master发送sync命令,传送整个数据文件覆盖到slave,后续有新数据产生时,master继续将新的数据收集到的修改命令依次传给slave,完成同步。会导致网络和系统繁忙。
还原配置:(50-53)
[root@51 ~]# vim /etc/redis/6379.conf
注释集群的相关配置
#cluster-enabled yes
#cluster-config-file nodes-6351.conf
[root@51 ~]# cd /var/lib/redis/6379/
删除库下的所有文件
配置一主一从
192.168.4.52:6379> info replication //查看主从配置信息
192.168.4.52:6379> SLAVEOF 192.168.4.51 6379 //临时添加为从库
永久设置在配置文件中添加这条语句
192.168.4.52:6379> SLAVEOF no one //手动设为主库
带验证的主从复制:
[root@51 6379]# vim /etc/redis/6379.conf
requirepass 123456 //主库指定验证密码
[root@52 6379]# vim /etc/redis/6379.conf
masterauth 123456 //从库指定主库密码
从库在访问主库数据时可以无密码访问,不设置就必须密码验证
配置一主多从
添加多个从库,几个从库的配置相同
[root@53 6379]# vim /etc/redis/6379.conf
282 slaveof 192.168.4.51 6351
289 masterauth 123456
配置主从从
将53配置52的从库,可以同步52的数据
哨兵模式:
主库宕机后,从库自动升级为主库。
[root@52 ~]# vim /etc/sentinel.conf
写入bind 0.0.0.0
sentinel monitor redis51 192.168.4.51 6351 1
sentinel auth-pass redis51 123456
Redis集群
集群模式是实际使用中最多的模式,在大流量访问的情况下能够提供稳定的业务,集群化是存储的必然形态。采用的无中心结构,每个节点保存数据和集群状态。至少包含3主3从。
容错性,是指软件检测应用程序或硬件中发生的错误并从错误中恢复的能力,可以从系统的可靠性、可用性、可测性来衡量。
- 搭建基本环境
50-56搭建redis服务,修改ip为每台对应的ip,端口为6350-6356,并启动
vim /etc/redis/6350.conf (集群参数)
Protected-mode no
#bind 192.168.4.50 //修改ip
port 6350 //不允许相同,只指定物理接口的ip
daemonize yes //以守护进程方式运行
pidfile /var/run/redis_6350.pid
Logfile “6350.log”
Mastrauth 123456
Requirepass 123456
cluster-enabled yes
cluster-config-file nodes-6350.conf
cluster-node-timeout 5000
启动后会出现两个端口
192.168.4.51:6350
192.168.4.51:16350
[root@51 soft]# ls /var/lib/redis/6350/
dump.rdb nodes-6350.conf
192.168.4.50:6350> CLUSTER info 查看集群基本信息
192.168.4.50:6350> CLUSTER nodes 查看集群连接信息
192.168.4.50:6350> info replication 查看基本信息
2.装包(以51做管理服务器)
[root@51 redis-cluster]# yum -y install ruby rubygems
[root@51redis-cluster]#rpm -ivh --nodeps ruby-devel-2.0.0.648-30.el7.x86_64.rpm
[root@51 redis-cluster]# gem install redis-3.2.1.gem
[root@51 redis-4.0.8]# cd src/
[root@51 src]# echo $PATH
[root@51 src]# mkdir /root/bin
[root@51 src]# cp redis-trib.rb /root/bin/
[root@51 src]# redis-trib.rb help - 创建集群
5版本
Redis-cli --cluster create -a 123456 192.168.4.50:6350 192.168.4.51:6351 192.168.4.52:6352 192.168.4.53:6353 192.168.4.54:6354 192.168.4.55:6355
–cluster-replicas 1
5版本以下
–replicas n ,自动为每一个master节点分配 n 个slave节点
[root@51 ~]# redis-trib.rb create --replicas 1 192.168.4.51:6351 192.168.4.52:6352 192.168.4.53:6353 192.168.4.54:6354 192.168.4.55:6355 192.168.4.56:6356
[OK] All 16384 slots covered.
192.168.4.51:6351> CLUSTER info //查看集群信息
192.168.4.51:6351> CLUSTER NODES //查看集群节点信息
排错:rm -rf /var/lib/redis/6379/nodes-xxx.conf
/etc/init.d/redis_6379 stop
/etc/init.d/redis_6379 start
4.测试集群
在客户端访问任意一台master主机存数据 redis-cli -c(集群模式) -h 地址 -p 端口
[root@50 redis-4.0.8]# redis-cli -c -h 192.168.4.51 -p 6351
在主库上能存取,在从库上只能查
[root@51 ~]# redis-trib.rb check 192.168.4.51:6351
redis-trib.rb脚本:
redis-trib.rb 选项 参数
– add-node 添加master主机
– check 检测集群
– reshard 重新分片
– add-node --slave 添加slave主机
– del-node 删除主机
master选举测试:
停止master 主机的 Redis服务,master宕机后对应的slave自动被选举为master,原master启动后会自动配置为当前master的slave
[root@51 ~]# redis-trib.rb check 192.168.4.51:6351
添加新节点:
添加master主机
把主机添加到集群中
装包– 初始化– 启用集群配置– 重启服务
– 添加master主机– 检查主机– 重新分片
添加时不指定主机角色,默认新主机被选为master
redis-trib.rb add-node 192.168.4.57:6357 192.168.4.51:6351(添加的主库)
redis-trib.rb check 192.168.4.51:6351
分配hash slots
[root@51 ~]# redis-trib.rb reshard 192.168.4.57:6357(分配槽给57)
– 指定移出hast槽个数
– 指定接收hash槽主机ID
– 指定移出hash槽主机ID
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 259dac09c97db713b3e4b8094eb99102d8418542
Please enter all the source node IDs.
Type ‘all’ to use all the nodes as source nodes for the hash slots.
Type ‘done’ once you entered all the source nodes IDs.
Source node #1:all
Do you want to proceed with the proposed reshard plan (yes/no)? yes
添加slave主机
如果不指定主节点的id 的话,会把新节点 随机添加为 从节点 最少的主的从
redis-trib.rb add-node --slave [ --master-id id值 ]
ip地址:端口 192.168.4.51:6351
[root@51 ~]# redis-trib.rb add-node --slave 192.168.4.58:6358 192.168.4.51:6351
[root@51 ~]# redis-trib.rb check 192.168.4.51:6351
移除节点:
先移除slave主机
从节点主机没有槽位范围,直接移除即可
redis-trib.rb del-node 192.168.4.51:6351 主机id值
[root@51 ~]# redis-trib.rb del-node 192.168.4.51:6351 b9fb596193094cc0312336b7683f040d912d71fb
移除master
先重新分片释放占用的hash槽
再移除master主机
重新分片释放占用的hash槽
– 指定移出hash槽个数
– 指定接收hash槽主机ID
– 指定移出hash槽主机ID
[root@51 ~]# redis-trib.rb reshard 192.168.4.51:6351
[root@51 ~]# redis-trib.rb check 192.168.4.51:6351
redis-trib.rb del-node 192.168.4.51:6351 master主机id值
[root@51 ~]#redis-trib.rb del-node 192.168.4.51:6351 259dac09c97db713b3e4b8094eb99102d8418542
将坏的主机加入集群,先删除nodes-6358.conf后重新启动,再加入集群。
redis+LNMP
1.安装软件包
安装nginx:
yum -y install gcc gcc-c++ pcre-devel zlib-devel
tar -zxf nginx-1.12.2.tar.gz
cd nginx-1.12.2
./configure --prefix=/usr/local/nginx
Make &&make install
安装mysql:
使用之前安装过的mysql服务
安装php:
yum -y install php-fpm-5.4.16-42.el7.x86_64.rpm(依赖包为 php-common)
2.启动服务
启动php-fpm:
[root@52 lnmp]# systemctl restart php-fpm.service
[root@52 lnmp]# systemctl status php-fpm.service
[root@52 lnmp]# ss -anpult |grep :9000
[root@52 lnmp]# systemctl enable php-fpm
启动nginx:
修改配置文件vim /usr/local/nginx/conf/nginx.conf
65 location ~ .php$ {
66 root html;
67 fastcgi_pass 127.0.0.1:9000;
68 fastcgi_index index.php;
69 # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
70 include fastcgi.conf;
71 }
[root@52 lnmp]# systemctl stop httpd
[root@52 lnmp]# /usr/local/nginx/sbin/nginx
[root@52 lnmp]# ss -anptul | grep :80
3.测试配置:
[root@52 lnmp]# vim /usr/local/nginx/html/test.php
[root@52 lnmp]# curl http://localhost/test.php
4.运行redis服务
tar -xzf redis-4.0.8.tar.gz
cd redis-4.0.8
Make&&make install
./utils/install_server.sh //初始化
/etc/init.d/redis_6379 status
[root@52 redis-4.0.8]# ss -anptul | grep 6379
[root@52 redis-4.0.8]# redis-cli
5.配置php支持redis
Yum -y install php
yum -y install autoconf automake
[root@52 redis]# yum -y install php-devel-5.4.16-42.el7.x86_64.rpm
tar -zxf php-redis-2.2.4.tar.gz
cd phpredis-2.2.4/
/usr/bin/phpize
./configure --with-php-config=/usr/bin/php-config
Make &&make install
Php -m 查看php支持的功能模块
Php -m |grep -i redis (还没有)
[root@52 phpredis-2.2.4]# vim /etc/php.ini
728 extension_dir = “/usr/lib64/php/modules/”
730 extension = “redis.so”
[root@52 phpredis-2.2.4]# systemctl restart php-fpm.service
[root@52 phpredis-2.2.4]# php -m |grep redis
6.测试配置
vim /usr/local/nginx/html/redis.php
[root@52phpredis-2.2.4]#curl http://localhost/redis.php
[root@52 phpredis-2.2.4]# redis-cli
127.0.0.1:6379> keys *
127.0.0.1:6379> get redistest