1、redis的数据结构
redis支持5种数据结构:
1、string(字符串)
2、list(字符串列表)
3、sets(字符串集合)
4、sorted sets(有序字符串集合)
5、hashes(哈希)
1.1、string
string是任何存储系统必备的数据类型,下面是一个简单例子:
字符串操作就是这么简单,而且因为是二进制安全,所以也可以存储图片,而且可以通过字符串类型进行数值操作
在遇到数值操作时,redis会自动将字符串转换为数值
由于incr等指令具有原子性操作的特性。所以我们可以使用incr、INCRBY、DECR、DECRBY等命令来进行原子计数的效果
1.2、lists
首先明确一点,lists在底层实现并不是数组,而是链表,也就是说对于一个具有上百万元素的lists在头部和尾部插入数据的时间复杂度是常数级别的,所以在将元素插入一个上百万元素的lists与插入一个只有10个元素的lists中的速度是一样的。
虽然lists有这样的优势,但也有其弊端,链表型lists比数组型lists定位要慢得多。
lists的基础操作有:lpush、rpush、lange等操作
1.3、集合
redis的集合是一种无序集合,集合中的元素是没有先后顺序的
集合的操作也相当丰富,如添加,删除已有元素,取交集,并集,差集
//向集合myset中加入一个新元素"one" 127.0.0.1:6379> sadd myset "one" (integer) 1 127.0.0.1:6379> sadd myset "two" (integer) 1 //列出集合myset中的所有元素 127.0.0.1:6379> smembers myset 1) "one" 2) "two" //判断元素1是否在集合myset中,返回1表示存在 127.0.0.1:6379> sismember myset "one" (integer) 1 //判断元素3是否在集合myset中,返回0表示不存在 127.0.0.1:6379> sismember myset "three" (integer) 0 //新建一个新的集合yourset 127.0.0.1:6379> sadd yourset "1" (integer) 1 127.0.0.1:6379> sadd yourset "2" (integer) 1 127.0.0.1:6379> smembers yourset 1) "1" 2) "2" //对两个集合求并集 127.0.0.1:6379> sunion myset yourset 1) "1" 2) "one" 3) "2" 4) "two"
1.4、有序集合
有序集合每个元素都关联一个序号(score),这是排序的标志
我们将有序集合叫做zset,因为有序集合中的操作都是以z开头的,比如zrange、zadd、zrevrange、zrangebyscore等等
127.0.0.1:6379> zadd myzset 1 baidu.com (integer) 1 //向myzset中新增一个元素360.com,赋予它的序号是3 127.0.0.1:6379> zadd myzset 3 360.com (integer) 1 //向myzset中新增一个元素google.com,赋予它的序号是2 127.0.0.1:6379> zadd myzset 2 google.com (integer) 1 //列出myzset的所有元素,同时列出其序号,可以看出myzset已经是有序的了。 127.0.0.1:6379> zrange myzset 0 -1 with scores 1) "baidu.com" 2) "1" 3) "google.com" 4) "2" 5) "360.com" 6) "3" //只列出myzset的元素 127.0.0.1:6379> zrange myzset 0 -1 1) "baidu.com" 2) "google.com" 3) "360.com"
1.5、哈希
hashes存的是字符串与字符串值之间的映射
//建立哈希,并赋值 127.0.0.1:6379> HMSET user:001 username antirez password P1pp0 age 34 OK //列出哈希的内容 127.0.0.1:6379> HGETALL user:001 1) "username" 2) "antirez" 3) "password" 4) "P1pp0" 5) "age" 6) "34" //更改哈希中的某一个值 127.0.0.1:6379> HSET user:001 password 12345 (integer) 0 //再次列出哈希的内容 127.0.0.1:6379> HGETALL user:001 1) "username" 2) "antirez" 3) "password" 4) "12345" 5) "age" 6) "34"
2、redis持久化 - 两种方式
redis提供了两种持久化方式,分别是RDB(又称快照)(Redis DataNase)与AOF(Append Only File)
RDB,简而言之,就是在不同的时间点上,将redis存储的数据生成快照,存储到磁盘等介质上
AOF,就是讲redis执行过的所有写指令记录下来,在一次redis重新启动时,将这些写指令从头到尾执行一遍,就可以将数据恢复过来。
RDB与AOF也可以同时使用,在这种情况下,如果redis重启的话,会优先使用AOF来进行数据恢复,应为AOF方式数据恢复度最高。如果没有持久化的需求,也可以关闭RDB与AOF,这样redis就变成了一个纯内存数据库。
2.1、RDB
RDB方式:是将redis某一时刻的数据持久化到磁盘中,是一种快照式的持久化方式
redis在进行持久化的过程中,会将数据先存入一个临时文件中,当持久化结束后,才会将该临时文件替换上次持久化好的文件。正是因为这种特性,我们可以随时进行备份,因为快照文件总是完整可用的。
对于RDB方式,redis会单独创建(fork)一个子进程来进行持久化,而主进程不会进行任何的IO操作,这样就保证了redis极高的性能
如果要进行大规模的数据恢复,且对数据完整性不是很敏感,那么RDB会很适合你
虽然RDB有很多优点,但是其缺点也是不可忽视的,如果你对数据完整性非常敏感,那么,RDB不适合你,因为RDB每5分钟进行一次备份,如果出现故障,那么会有将近5分钟的数据丢失。所以redis还提供了另一种数据持久化方式--AOF
2.1、AOF
AOF(Append Only File):即只允许追加,不允许改写的文件
如前面介绍的那样,AOF就是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序将指令在执行一遍。
我们通过配置redis.conf中的appendonly yes就可以开启AOF功能,如果有写操作(set)就会被追加到AOF文件中
默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis仍然可以保持很好的性能,即使redis故障,也只会丢失一秒的数据
如果在追加日志时,碰到磁盘空间满的情况、inode满或断电的情况导致日志写入不完整,也没有关系,redis提供了redis-check-aof工具,可以用来进行日志的修复
因为采用了追加方式,如果不做任何处理的话,AOF文件会越来越大,为此,redis提供了AOF文件重写的机制,即当AOF文件的大小超过指定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。如:我们调用了100次incr指令,但是AOF文件中就是要存储100条指令,这明显是很低效的,完全可以将这100条指令合并成一条SET指令,这就是重写机制的原理。
在进行AOF重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以在断电、磁盘满等情况都不会影响AOF文件的可用性。
AOF的另一个好处是:如果你在操作redis时,不小心执行了FLUSHALL命令,导致redis内存中的数据全部清空了,只要配置了AOF,且AOF文件还没有被重写,我们就可以用最快的方式暂停redis并编辑AOF文件,将AOF文件中最后一行的FLUSHALL命令删除,然后重启redis,就可以将redis数据恢复到FLUSHALL命令执行之前。这就是使用AOF进行持久化的好处之一,但是如果AOF文件被重写了,那么就无法通过这种方式来恢复数据。
然而,AOF也有缺点,例如,在同等数据规模下,AOF文件比RDB文件规模更大,而且,恢复数据的速度也远远慢与RDB。
如果运气比较差,出现了AOF文件被写坏的情况,也不必过于担忧,redis不会贸然加载这个有问题的文件而是报错退出,这时可以通过以下步骤来修复出错的文件:
1、备份被写坏的文件
2、运行redis-check-aof-fix进行修复
3、用diff-u来看下两个文件的差异,确认问题点
4、重启redis,加载修复后的文件
未完待续