Redis

Redis

https://www.runoob.com/redis/redis-tutorial.html

安装

下载最新版redis-X.Y.Z.tar.gz后解压,然后进入redis-X.Y.Z文件夹后直接make即可,安装非常简单。make成功后会在src文件夹下产生一些二进制可执行文件,包括redis-server、redis-cli等等:

$ find . -type f -executable
./redis-benchmark //用于进行redis性能测试的工具
./redis-check-dump //用于修复出问题的dump.rdb文件
./redis-cli //redis的客户端
./redis-server //redis的服务端
./redis-check-aof //用于修复出问题的AOF文件
./redis-sentinel //用于集群管理

启动Server、启动Client、get set、shutdown

./redis-server
    
./redis-cli //启动redis客户端

PING //PING命令,该命令用于检测redis服务是否启动,已启动返回PONG。
  
redis-cli -h host -p port -a password //远程redis服务上执行

shutdown //关闭

Redis数据结构

redis是一种高级的key:value存储系统,其中value支持五种数据类型:

1.字符串(strings)
2.字符串列表(lists)
3.字符串集合(sets)
4.有序字符串集合(sorted sets)
5.哈希(hashes)

Strings

https://www.runoob.com/redis/redis-strings.html

二进制安全

demo

set name "zbn" //set设置key,value
get name //getvalue

Lists

https://www.runoob.com/redis/redis-lists.html

redis中的lists在底层实现上并不是数组,而是链表,也就是说对于一个具有上百万个元素的lists来说,在头部和尾部插入一个新元素,其时间复杂度是常数级别的,比如用LPUSH在10个元素的lists头部插入新元素,和在上千万元素的lists头部插入新元素的速度应该是相同的。

虽然lists有这样的优势,但同样有其弊端,那就是,链表型lists的元素定位会比较慢,而数组型lists的元素定位就会快得多。

demo

lpush mylist "1" //在列表mylist头部插入元素"1"
(integer) 1 //返回当前mylist中的元素个数
  
rpush mylist "2" //在mylist尾部插入元素"2"
(integer) 2 //返回当前mylist中的元素个数

lrange mylist 0 1 //列出mylist中从编号0到编号1的元素
1) "0"
2) "1"

lrange mylist 0 -1 //列出mylist中从编号0到倒数第一个元素
1) "0"
2) "1"
3) "2"

Sets

https://www.runoob.com/redis/redis-sets.html

redis的集合,是一种无序的集合,集合中的元素没有先后顺序。

demo

sadd myset "one" //向集合myset中加入一个新元素"one"
(integer) 1 //返回被添加到集合中的新元素的数量
sadd myset "two"
(integer) 1
  
smembers myset //列出集合myset中的所有元素
1) "one"
2) "two"
  
sismember myset "one" //判断元素"one"是否在集合myset中,返回1表示存在
(integer) 1

sismember myset "three" //判断元素"three"是否在集合myset中,返回0表示不存在
(integer) 0

sadd yourset "1" //新建一个新的集合yourset
(integer) 1
sadd yourset "2"
(integer) 1
smembers yourset
1) "1"
2) "2"

sunion myset yourset //对两个集合求并集
1) "1"
2) "one"
3) "2"
4) "two"

Sorted Sets

https://www.runoob.com/redis/redis-sorted-sets.html

redis不但提供了无需集合(sets),还很体贴的提供了有序集合(sorted sets)。有序集合中的每个元素都关联一个序号(score),这便是排序的依据。

很多时候,我们都将redis中的有序集合叫做zsets,这是因为在redis中,有序集合相关的操作指令都是以z开头的。

demo

zadd myzset 1 baidu.com //新增一个有序集合myzset,并加入一个元素baidu.com,给它赋予的序号是1:
(integer) 1 //返回被添加到集合中的新元素的数量
zadd myzset 2 google.com //向myzset中新增一个元素google.com,赋予它的序号是2
(integer) 1
zadd myzset 3 360.com //向myzset中新增一个元素360.com,赋予它的序号是3
(integer) 1

zrange myzset 0 -1 with scores //列出myzset的所有元素,同时列出其序号,可以看出myzset已经是有序的了。
1) "baidu.com"
2) "1"
3) "google.com"
4) "2"
5) "360.com"
6) "3"

zrange myzset 0 -1 //只列出myzset的元素
1) "baidu.com"
2) "google.com"
3) "360.com

Hashes

https://www.runoob.com/redis/redis-hashes.html

hashes存的是字符串和字符串值之间的映射。

demo

HMSET user:001 username antirez password P1pp0 age 34 //建立哈希,并赋值
OK
  
HGETALL user:001 //列出哈希的内容
1) "username"
2) "antirez"
3) "password"
4) "P1pp0"
5) "age"
6) "34"

HSET user:001 password 12345 //更改哈希中的某一个值
(integer) 0 //覆盖旧域返回0,设置一个新域返回1
HGETALL user:001 //再次列出哈希的内容
1) "username"
2) "antirez"
3) "password"
4) "12345"
5) "age"
6) "34"

Redis持久化

redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)

RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;

AOF,则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

其实RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。

如果你没有数据持久化的需求,也完全可以关闭RDB和AOF方式,这样的话,redis将变成一个纯内存数据库。

RDB

RDB方式,是将redis某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。

redis在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。

对于RDB方式,redis会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何IO操作的,这样就确保了redis极高的性能。

如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

虽然RDB有不少优点,但它的缺点也是不容忽视的。如果你对数据的完整性非常敏感,那么RDB方式就不太适合你,因为即使你每5分钟都持久化一次,当redis故障时,仍然会有近5分钟的数据丢失。所以,redis还提供了另一种持久化方式,那就是AOF。

AOF

AOF,英文是Append Only File,即只允许追加不允许改写的文件。

如前面介绍的,AOF方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。

我们通过配置redis.conf中的appendonly yes就可以打开AOF功能。如果有写操作(如SET等),redis就会被追加到AOF文件的末尾。

默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis仍然可以保持很好的处理性能,即使redis故障,也只会丢失最近1秒钟的数据。

如果在追加日志时,恰好遇到磁盘空间满、inode满或断电等情况导致日志写入不完整,也没有关系,redis提供了redis-check-aof工具,可以用来进行日志修复。

因为采用了追加方式,如果不做任何处理的话,AOF文件会变得越来越大,为此,redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了100次INCR指令,在AOF文件中就要存储100条指令,但这明显是很低效的,完全可以把这100条指令合并成一条SET指令,这就是重写机制的原理。

在进行AOF重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响AOF文件的可用性,这点大家可以放心。

AOF方式的另一个好处,我们通过一个“场景再现”来说明。某同学在操作redis时,不小心执行了FLUSHALL,导致redis内存中的数据全部被清空了,这是很悲剧的事情。不过这也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件还没有被重写(rewrite),我们就可以用最快的速度暂停redis并编辑AOF文件,将最后一行的FLUSHALL命令删除,然后重启redis,就可以恢复redis的所有数据到FLUSHALL之前的状态了。是不是很神奇,这就是AOF持久化方式的好处之一。但是如果AOF文件已经被重写了,那就无法通过这种方法来恢复数据了。

虽然优点多多,但AOF方式也同样存在缺陷,比如在同样数据规模的情况下,AOF文件要比RDB文件的体积大。而且,AOF方式的恢复速度也要慢于RDB方式。

如果你直接执行BGREWRITEAOF命令,那么redis会生成一个全新的AOF文件,其中便包括了可以恢复现有数据的最少的命令集。

如果运气比较差,AOF文件出现了被写坏的情况,也不必过分担忧,redis并不会贸然加载这个有问题的AOF文件,而是报错退出。这时可以通过以下步骤来修复出错的文件:

1.备份被写坏的AOF文件
2.运行redis-check-aof –fix进行修复
3.用diff -u来看下两个文件的差异,确认问题点
4.重启redis,加载修复后的AOF文件

AOF重写的内部运行原理

在重写即将开始之际,redis会创建(fork)一个“重写子进程”,这个子进程会首先读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。

与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。

当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。

当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中了。

主从

像MySQL一样,redis是支持主从同步的,而且也支持一主多从以及多级从结构。

主从结构,一是为了纯粹的冗余备份,二是为了提升读性能,比如很消耗性能的SORT就可以由从服务器来承担。

redis的主从同步是异步进行的,这意味着主从同步不会影响主逻辑,也不会降低redis的处理性能。

主从架构中,可以考虑关闭主服务器的数据持久化功能,只让从服务器进行持久化,这样可以提高主服务器的处理性能。

在主从架构中,从服务器通常被设置为只读模式,这样可以避免从服务器的数据被误修改。但是从服务器仍然可以接受CONFIG等指令,所以还是不应该将从服务器直接暴露到不安全的网络环境中。如果必须如此,那可以考虑给重要指令进行重命名,来避免命令被外人误执行。

事务处理

https://www.runoob.com/redis/redis-transactions.html

众所周知,事务是指“一个完整的动作,要么全部执行,要么什么也没有做”。

MULTI、EXEC、DISCARD、WATCH四个指令构成了redis事务处理的基础。

1.MULTI用来组装一个事务;
2.EXEC用来执行一个事务;
3.DISCARD用来取消一个事务;
4.WATCH用来监视一些key,一旦这些key在事务执行之前被改变,则取消事务的执行。(UNWATCH用于取消WATCH 命令对所有 key 的监视。)

demo

MULTI //标记事务开始
OK
  
INCR user_id //多条命令按顺序入队
QUEUED
INCR user_id
QUEUED
INCR user_id
QUEUED

EXEC //执行
1) (integer) 1
2) (integer) 2
3) (integer) 3

在上面的例子中,我们看到了QUEUED的字样,这表示我们在用MULTI组装事务时,每一个命令都会进入到内存队列中缓存起来,如果出现QUEUED则表示我们这个命令成功插入了缓存队列,在将来执行EXEC时,这些被QUEUED的命令都会被组装成一个事务来执行。

对于事务的执行来说,如果redis开启了AOF持久化的话,那么一旦事务被成功执行,事务中的命令就会通过write命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,那么就可能出现只有部分命令进行了AOF持久化,这时AOF文件就会出现不完整的情况,这时,我们可以使用redis-check-aof工具来修复这一问题,这个工具会将AOF文件中不完整的信息移除,确保AOF文件完整可用。

有关事务,大家经常会遇到的是两类错误:

1.调用EXEC之前的错误
2.调用EXEC之后的错误

“调用EXEC之前的错误”,有可能是由于语法有误导致的,也可能时由于内存不足导致的。只要出现某个命令无法成功写入缓冲队列的情况,redis都会进行记录,在客户端调用EXEC时,redis会拒绝执行这一事务。

demo

multi
OK

haha //一个明显错误的指令
(error) ERR unknown command 'haha'

exec 
(error) EXECABORT Transaction discarded because of previous errors //redis无情的拒绝了事务的执行,原因是“之前出现了错误”

“调用EXEC之后的错误”,redis则采取了完全不同的策略,即redis不会理睬这些错误,而是继续向下执行事务中的其他命令。这是因为,对于应用层面的错误,并不是redis自身需要考虑和处理的问题,所以一个事务中如果某一条命令执行失败,并不会影响接下来的其他命令的执行。

demo
  
multi
OK
set age 23
QUEUED
sadd age 15 //age不是集合,所以是一条明显错误的指令
QUEUED
set age 29
QUEUED
exec //执行事务时,redis不会理睬第2条指令执行错误
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
get age
"29" //可以看出第3条指令被成功执行了

“WATCH”是一个很好用的指令,它可以帮我们实现类似于“乐观锁”的效果,即CAS(check and set)。

WATCH本身的作用是“监视key是否被改动过”,而且支持同时监视多个key,只要还没真正触发事务,WATCH都会尽职尽责的监视,一旦发现某个key被修改了,在执行EXEC时就会返回nil,表示事务无法触发。

demo

set age 23
OK
watch age //开始监视age
OK
set age 24 //在EXEC之前,age的值被修改了
OK
multi
OK
set age 25
QUEUED
get age
QUEUED
exec //触发EXEC
(nil) //事务无法被执行

Redis配置

redis只支持bytes,不支持bit单位。

redis配置文件被分成了几大块区域,分别是:

1.通用(general)
2.快照(snapshotting)
3.复制(replication)
4.安全(security)
5.限制(limits)
6.追加模式(append only mode)
7.LUA脚本(lua scripting)
8.慢日志(slow log)
9.事件通知(event notification)

Redis 服务器

https://www.runoob.com/redis/redis-server.html

用于管理 redis 服务。

Redis GEO

https://www.runoob.com/redis/redis-geo.html

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作。

Redis GEO 操作方法有:

  • geoadd:添加地理位置的坐标。
  • geopos:获取地理位置的坐标。
  • geodist:计算两个位置之间的距离。
  • georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
  • georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
  • geohash:返回一个或多个位置对象的 geohash 值。
demo
  
geoadd Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2

geodist Sicily Palermo Catania
"166274.1516"

georadius Sicily 15 37 100 km
1) "Catania"
georadius Sicily 15 37 200 km
1) "Palermo"
2) "Catania"
  
geopos Sicily Palermo Catania
1) 1) "13.36138933897018433"
   2) "38.11555639549629859"
2) 1) "15.08726745843887329"
   2) "37.50266842333162032"

Redis Stream

https://www.runoob.com/redis/redis-stream.html

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

Redis Stream

https://www.runoob.com/redis/redis-stream.html

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

img

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值