redis学习笔记
redis学习笔记
安装
- 下载
- 方式一
1. 获取安装源
wget http://download.redis.io/releases/redis-5.0.3.tar.gz
2. 解压
tar zxvf redis-4.0.8.tar.gz
- 方式二
官网: https://redis.io/download
1、选择Stable(5.0)下的Download 5.0.3 链接进行下载 (stable是稳定版本,默认下载的是linux版本)
2、下载完成之后,打开xftp,把我们下载好的Redis压缩包,上传到Linux的 /root/ 文件目录下
- 进入到redis目录下
[root@localhost redis-5.0.3]# cd redis-5.0.3
[root@localhost redis-5.0.3]# make
这里输入make如果没有安装会报错
安装GCC
由于redis是由C语言编写的,它的运行需要C环境,因此我们需要先安装gcc。安装命令如下:
[root@localhost redis-5.0.3]# yum install gcc-c++
[root@localhost redis-5.0.3]# make //对解压后的文件进行编译
[root@localhost redis-5.0.3]# cd ./src //进入到 redis-5.0.3/src 文件目录下
[root@localhost src]# make install //进行redis安装
[root@localhost src]# mv redis.conf ./root/myredis
[root@localhost src]# vim ./root/myredis/redis.conf
#将文件中的daemonize on改为yes,配置redis为后台启动
- 启动
[root@localhost redis-5.0.3]# cd /usr/local/bin #在指定目录下跑
[root@localhost bin]# redis-server /root/myredis/redis.conf
[root@localhost ~]# redis-cli -p 6379
4. 测试
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set k1 hello
OK
127.0.0.1:6379> get k1
"hello"
127.0.0.1:6379>
- 关闭
127.0.0.1:6379> shutdown
基础知识
- redis是单进程的
- 默认16个数据库,类似于数组下标从0开始,初始默认使用0号数据库
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
- select命令切换数据库
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> get k1
(nil)
- DBSIZE获取当前数据库的key数量
127.0.0.1:6379> DBSIZE
(integer) 1
127.0.0.1:6379> keys * # 查看所有key
1) "k1"
127.0.0.1:6379> set k2 Hi
OK
127.0.0.1:6379>set k v
- FLUSHDB 删除当前库数据
- FLUSHALL删除所有库数据
- 统一密码管理,16个库都是同样的密码
- Redis索引都是从0开始
- 默认端口6379
redis的数据类型
redis的五大数据类型
1. String(字符串)
- String类型是redis的基本类型,与memcached一模一样的类型,一个key对应一个value
- String是二进制安全的。意思为redis的String可以包含任意数据,比如jpg图片、序列化对象等
- 一个redis的字符串value最多是512M
2. Hash(哈希类似于Map) - 是一个键值对集合,
- redis hash是一个String类型的field和value的映射表,hash特别适用于存储对象
- 类似于Map<String,Object>
3. Set(集合)
4. List(列表)
5. Zset(有序集合)
常见数据类型操作命令
1. Redis键(Key)
keys * //查看全部key
exists key的名字 //判断某个key是否存在
move key db //移除当前库
expire key 秒钟 //为给定key设置过期时间
ttl key //查看key过期时间,-1为永不过期,-2为已过期
type key //查看key的类型
2.String
set/del/get/append/strlen
Incr(加1)/decr(减一)/incrby(incrby k1 3:每次加3)/decrby #一定要是数字才能进行加减
getrange/setrange #getrange获取指定区间的值,类似于between···and
setex(set with expire)键秒值/setnx(set is no exist)
mset/mget/msetnx
getset(先get在set)
3. List
lpush(从左输入)/rpush(从右输入)/lrange(从左输出)
lpop(出栈从左边开始出)/rpop
lindex # 按照索引下标获取值(从上到下)
llen #获取list长度
lrem key # 删除N个value lrem list01 1 2 (从list中删除一个2)
ltrim key 开始index 结束index #截取指定范围的值,并赋值给key
rpoplpush 源列表 目的列表 # 将源列表的最下面的弹出,放到目的列表的最上面
lset key index value # 把下标为index的换成value
linsert key before/after 值1 值2 # 将值2插入到值1前或后
总结:
- 它是一个字符串链表,左右都可以插入添加
- 如果键不存在,创建新的链表
- 如果键存在,添加内容
- 如果值全部移除对应的键有没有了
- 链表的操作,无论是头和尾效率都极高,但如果对中间元素操作,效率就比较慢了
** 4.set**
sadd/smembers/sismember # 向集合中添加元素,smembers查看集合中元素
scrsd # 查看set中元素个数
srem key value # 删除结合中的元素
srandmember key 某个整数 # 随机出几个数
spop key 整数 # 随机出栈整数个
smove key1 key2 value # 将key1中的value移动到key2
sdiff key1 key2··· # 差集:在前面一个集里面,但不在后面任何一个集里面
sinter # 交集
sunion # 并集
5.Hash
hset/hget/hmset/hmget/hgetall/hdel # hset插入、hget获取
hlen #获取长度
hexists key 在key里面的某个值的key #判断key里面是否含有某个键
hkeys/hvals # 查看hash全部的key和valus
hincrby/hincrbyfloat # 数值增加
hsetnx # 插入键值对
6.Zset
zadd/zrange #zadd插入,zrange 显示zrange 0 -1 withscores 连值带value显示
zrangebyscore key 开始score 结束score # 展示开始和结束的区间内的值:withscores 展示全部,(:不包含 ;limit 相当于分页的limit
zrem key 某个score下对应的value # 删除某个value
zcrad/zcount key score区间 /zrank key values值 :获取下标值/zscore key 对应值 :获取分数
zrevrank key values # 逆序获取下标值
zrevrange
zrevrangebyscore key 结束score 开始score
redis的配置文件
持久化
RDB(Redis DataBase)
- 在指定的时间间隔内将内存中的数据集快照写入磁盘,即Snapshot,它恢复时是讲快照文件直接读到内存里面
- Redis会单独创建(fork)一个子进程来完成持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化的文件,整个过程中,主进程不进行任何IO操作,这确保了极高的性能
- 如果需要进行大规模数据的恢复,且对数据恢复的完整性不是非常敏感,那RDB方式要比AOF高效。RDB的缺点是最后一次持久化的数据可能丢失
fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值和原进程一致,但是是一个全新的进程,并作为原进程的子进程
如何触发RDB快照
- 配置文件的默认快照配置:冷拷贝(从主机拷贝到备用机上)后重新使用,可以使用
cp dump.rdb dump_new.rdb
- 命令是save或者bgsave(直接在命令上输入save可以直接保存、bgsave指异步)
- 执行FLUSHALL命令也会产生dump.rdb,但是里面是空的,无意义
如何恢复
将备份文件(dump.rdb)移动到redis的安装目录,并启动服务即可(config get dir :获取目录)
优势
- 适合大规模数据恢复
- 对数据一致性和完整性要求不高
劣势
- 最后一次持久化的数据可能丢失
- Fork的时候,内存中的数据被扩容一份,大致2倍的膨胀性需要考虑
如何停止
动态停止所有RDB保存规则的方法:redis-cli config set save “”
AOF(Append only File)
以日志形式记录每一个写操作
,将redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次完成数据的恢复工作
默认是关闭的
注:aof 会把FLUSHALL记录;
如果再某个过程中redis突然崩了,导致aof文件里面记录的数据存在问题了;当重启redis后无法成功启动(当aof文件及rdb同时存在,且配置问开启了aof,redis恢复使用aof),这时需要修复aof文件,可以使用如下命令进行修复
[root@localhost bin]# redis-check-aof --fix appendonly.aof
修复后重启即可
AOF启动/修复/恢复
- 启动:将redis.conf配置文件中的
appendonly on
改为appendonly yes
- 将有数据的aof文件复制一份到保存到对应的目录
- 恢复:重启redis然后重新加载
异常恢复 - 备份被写坏的aof文件
- 修复
redis-check-aof --fix appendonly.aof
-
- 恢复:重启redis然后重新加载
Rewrite
- AOF采用文件追加方式,文件会越来越大为避免此种情况,新增了重写机制,当AOF文件大小超过所设定的阈值时,redis就会启动AOF的文件内容压缩,只保留可以恢复的数据和最小指令集,可以使用bgwriteaof
- 原理:AOF持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件然后rename),遍历新进程中内存中的数据,每条记录有一条set语句。重写AOF文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
- 触发机制:Redis会记录上次重写时的AOF文件大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大小超过64M时触发
优势
- 每秒同步appendfsync always 同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差,但数据完整性较高
- 每同步修改 appendfsync everysec:异步操作,每秒记录,如果一秒内宕机,有数据丢失
- 不同步 appendfsync no 从不同步
劣势
- 相同数据集的数据而言,aof文件要远大于rdb文件,且恢复速度也慢与rdb
- aof运行效率要比rdb慢,每秒同步策略效率比较好,不同步效率和rdb相同
总结:同时开启两种持久化方式:当redis重启的时候优先载入AOF文件来恢复原始数据,
因为通常情况下AOF文件保存的数据集比RDB保存的完整性更高。
RDB的数据不实时,同时使用两者时,服务器重启也只会找AOF文件,那要不要只使用AOF持久化呢?
作者建议不要(redis作者),因为RDB更适合用于备份数据库(AOF不断变化,不好备份)。快速重启,而且不会有AOF可能存在的bug,可以留着作为一个万一的手段
Redis事务
- 事务是指可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序的串行化执行,而不会被其他命令插入,不允许加塞
- 在一个队列中,一次性、顺序性、排他性的执行一系列命令
实现及操作
#常用命令
DISCARD #取消事务
EXEC # 执行所有事务快内命令
MULTI # 标记一个事务块的开始
UNWATCH # 取消WATCH对所有key的监听
WATCH key [key...] # 对一个key或多个进行监听,如果在这个事务执行前,这个(或这些)key被其他命令所改动,那么事务将被打断
正常执行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v1"
4) OK
放弃事务
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 123
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> get k2
"v2"
全体连坐:只要有一个命令错了,就全部不能执行:(error) EXECABORT Transaction discarded because of previous(抛出异常)
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 c1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> setget k3
(error) ERR unknown command `setget`, with args beginning with: `k3`,
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
"v1"
冤头债主:谁错找谁,有错的就错的,没有错的可以继续执行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incr k1 # k1为字符,不能加1
QUEUED
127.0.0.1:6379> set k2 222
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> get k4
QUEUED
127.0.0.1:6379> EXEC
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "v4"
watch监控
乐观锁/悲观锁/CAS(Check And Set)
- 乐观锁:即每次拿数据都认为别人不会修改,所以每次拿数据的时候都不上锁,但是在更新的时候会判断在此期间有没有别更新了这个数据,可以使版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
乐观锁策略:提交版本必须大于记录当前版本才能执行更新
- 悲观锁:即每次拿数据都认为别人会修改,所以每次拿数据的时候都会上锁,这样别想拿数据的时候就会block直到拿到锁。传统的关系型数据库就用了很多这种锁机制:行锁、表锁、读锁、写锁等,都是在操作前先上锁
- CAS:检查并修改(一般用来解决aba问题)如果版本号为预期指则修改
在两个终端中进行操作被监控的数据,事务不能提交成功
- watch指令类似于乐观锁,事务提交时,如果key的值已经被别的客户端修改过了,比如某个list被push/pop过了,那么这个事务都不会被执行
- 通过watch命令在事务执行前监控多个key,倘若watch后有任何一个key的值发生了变化,那么exec命令执行是事务都会放弃,同时返回nullmulti-bulk应答以通知调用者事务执行失败
小结
事务的三个阶段
- 开启:以MULTI开启一个事务
- 入队:多个命令进入队列,这些命令不是立刻执行,而是出于等待状态
- 执行:EXEC命令触发队列里面的命令执行
事务的三个特性
- 单独的隔离操作:事务中的所有命令都会序列化、按顺序的执行。事务在执行过程中,不会被其他客户端发送来的请求打断
- 没有隔离级别概念:队列中的命令没有提交之前都不会被执行,因为事务提交前所有命令都没有实际执行,所以也就不存在“事务内的查询要看到事务里的更新,在事务外要看不到”的问题
- 不保证原子性:redis中同一个事务中,如果一条命令执行失败,其后的命令 仍然会被执行,没有会滚
发布订阅
- 是什么:进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接受消息
- 命令
# 订阅一个或多个符合给定模式的频道
PSUBSCRIBE pattern [pattern ...]
# 查看订阅与发布系统状态
PUBSUB subcommand [argument [argument ...]]
# 将消息发送到指定频道
PUBLISH channel message
# 退订给定模式的所有频道
PUNSUBSCRIBE [pattern [pattern ...]]
#订阅给定的一个或多个频道信息
PUNSUBSCRIBE [pattern [pattern ...]]
# 退订给定的频道
UNSUBSCRIBE [channel [channel ...]]
主从复制
- 主机数据更新后,根据配置和策略,自动同步到备机的master/slaver机制,master以写为主,slaver以读为主
- 能够实现:读写分离,容灾恢复
- 使用:1、配从(库)不配主(库);2、从库配置:slaveof 主库ip 主库端口 ;3、修改配置文件;4、常用:一主二辅、薪火相传、反客为主
- 主机出现故障后,备机会一直等主机,备机出现故障和主机断开连接后,需要重新连接(除非写入到配置文件中)
一主二从
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
3) "k3"
4) "balance2"
5) "balance1"
6) "balance"
7) "k4"
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_replid:7440e41b9f31499c246fd937fd318edf8a162b2e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> get k2
"222"
从机(展示一个):
127.0.0.1:6380> keys *
(empty list or set)
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_replid:1c8ad610ffe2f60d4b64e25cfbf4d81cc6fc22af
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6380> get k1
"v1"
127.0.0.1:6380> keys *
1) "k3"
2) "balance2"
3) "k2"
4) "k4"
5) "balance"
6) "k1"
7) "balance1"
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:210
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:4baacb14df32d688b95ae21b170a91c2a7e5db64
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210
127.0.0.1:6380>
薪火相传
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
127.0.0.1:6381> SLAVEOF 127.0.0.1 6380
反客为主
127.0.0.1:6380> SLAVEOF no one
运行上面命令后,丛机变为主机
复制原理
- slave启动成功连接到master后,会发送一个sync命令
- master接受到命令启动后台存盘进程,同时收集所有接受到的用于用于修改数据集命令,在后台进程执行完毕后,master将传送整个数据文件到slave,以完成一次全量同步
- 全量复制:slave服务接受到数据库数据文件后,将其存盘并加载到内存中
- 增量复制:master继续将新的所有收集到的修改命令依次传递给slave,完成同步
- 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
哨兵模式
主机挂了,自动版的反客为主;能够后台监控主机是否故障,如果故障了,根据投票数自动将从库转化为主库
设置
- 模式依旧是一主二从;在配置文件目录下新建sentinel.conf文件(名字要对)
- 配置哨兵,填写内容:sentinel monitor被监控数据库名字 127.0.0.1 6379 1(1表示主机挂机后slave投票看让谁接替成为主机,得票数多者)
- 启动哨兵
主机出故障后,投票选出从机变为主机后,主机修复后,会变为选出的主机的从机
复制延时:由于所有写操作都是在master上操作,然后同步到slave上,所以从master同步到slave机器存在一定的延时,当系统很繁忙时,延迟问题会更加严重,slave机器数量增加也会使这个问题更加严重