一、什么是Redis?
Redis是C语言开发的一个开源的(遵从BSD协议)高性能键值对(key-value)的内存数据库,是一种No-SQL数据库。可以用作数据库、缓存、消息中间件等。
Redis作为一个内存数据库,有以下特点:
1、性能优秀,数据在内存中,读写速度非常快,支持并发10WQPS;
2、单进程单线程,是线程安全的,采用IO多路复用机制;
3、支持多种数据类型;
4、支持数据持久化;
5、通过主从复制,哨兵实现高可用。
Redis为什么快?
首先,采用了多路复用io阻塞机制
然后,数据结构简单,操作节省时间
最后,数据在内存中,读写速度自然快
除此之外,还有底层的数据结构SDS、跳跃表等等
为什么Redis是单线程的?
官方的说法是因为Redis的瓶颈不是cpu的运行速度,而往往是网络带宽和机器的内存大小,而且避免了线程上下文切换所需要的开销,单线程也更容易实现。
二、Redis支持五种基本数据类型:
String, Hash, List, Set, ZSet
1.String(字符串),Redis最基本的数据类型,一个Key对应一个Value
示例
redis 127.0.0.1:6379> SET name "runoob"
OK
redis 127.0.0.1:6379> GET name
"runoob"
2.Hash(哈希),适合用于存储对象
示例
redis 127.0.0.1:6379> HSET myhash field1 "Hello" field2 "World"
OK
redis 127.0.0.1:6379> HGET myhash field1
"Hello"
redis 127.0.0.1:6379> HGET myhash field2
"World"
3.List(列表),实现为一个双向链表,可以用作消息队列
示例
redis 127.0.0.1:6379> lpush runoob redis
(integer) 1
redis 127.0.0.1:6379> lpush runoob mongodb
(integer) 2
redis 127.0.0.1:6379> lpush runoob rabitmq
(integer) 3
redis 127.0.0.1:6379> lrange runoob 0 10
1) "rabitmq"
2) "mongodb"
3) "redis"
4.Set(集合),无序集合
示例:交集、并集、差集
//book表存储book名称
set book:1:name ”The Ruby Programming Language”
set book:2:name ”Ruby on rail”
set book:3:name ”Programming Erlang” //tag表使用集合来存储数据,因为集合擅长求交集、并集
sadd tag:ruby 1 sadd tag:ruby 2 sadd tag:web 2 sadd tag:erlang 3
//既属于ruby又属于web的书
inter_list = redis.sinter("tag:web", "tag:ruby")
//属于ruby,但不属于web的书
inter_list = redis.sdiff("tag:ruby", "tag:web")
//属于ruby 或者 属于web的书
inter_list = redis.sunion("tag:ruby", "tag:web")
5.Zset(有序列表)
示例
redis 127.0.0.1:6379> zadd runoob 0 redis
(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 mongodb
(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 rabitmq
(integer) 1
redis 127.0.0.1:6379> zadd runoob 0 rabitmq
(integer) 0
redis 127.0.0.1:6379> > ZRANGEBYSCORE runoob 0 1000
1) "mongodb"
2) "rabitmq"
3) "redis"
各个数据类型应用场景:
类型 | 简介 | 特性 | 场景 |
---|---|---|---|
String(字符串) | 二进制安全 | 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M | --- |
Hash(字典) | 键值对集合,即编程语言中的Map类型 | 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) | 存储、读取、修改用户属性 |
List(列表) | 链表(双向链表) | 增删快,提供了操作某一段元素的API | 1、最新消息排行等功能(比如朋友圈的时间线) 2、消息队列 |
Set(集合) | 哈希表实现,元素不重复 | 1、添加、删除、查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 | 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐 |
Sorted Set(有序集合) | 将Set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行天然排序 | 1、排行榜 2、带权重的消息队列 |
三、高级数据类型
1.Bitmaps
提供对位的操做。Bitmaps自己不是一种数据结构,实际上就是字符串,可是它能够对字符串的位进行操做。能够把Bitmaps想象成一个以位为单位数组,数组中的每一个单元只能存0或者1,数组的下标在bitmaps中叫作偏移量。单个bitmaps的最大长度是512MB,即2^32个比特位。
2.HyperLogLog
做基数统计,不会保存元数据,只记录数量而不是数值,能够使用极少的内存来统计巨量的数据,在 Redis 中实现的 HyperLogLog,只需要12K内存就能统计2^64个数据。计数存在一定的误差,误差率整体较低。标准误差为 0.81% 。误差可以被设置辅助计算因子进行降低。
3.GEO
提供了地理位置相关的一些运算操作。Geo本身不是一种数据结构,它本质上还是借助于Sorted Set(ZSET),并且使用GeoHash技术进行填充。
四、持久化
RDB + AOF
1.RDB 镜像全量持久化(数据快照)
将某个时间点的所有数据都存放到硬盘上。可以将快照复制到其它服务器从而创建具有相同数据的服务器副本。如果系统发生故障,将会丢失最后一次创建快照之后的数据。如果数据量很大,保存快照的时间会很长。
save:会阻塞redis服务器进程,直到创建RDB文件完毕为止;(在此期间进程不能处理任何请求)
bgsave:fork一个子进程来创建RDB文件,父进程可以继续处理命令请求;
一般不会直接save,基本都是用bgsave
2.AOF 增量持久化
AOF步骤:
命令追加:服务器在执行完一个写命令后,会以协议的格式把其追加到aof_buf缓冲区末尾;
文件写入:redis服务器进程就是一个事件循环,在每次事件循环结束,会根据配置文件中的appednfsync属性值决定是否将aof_buf中的数据写入到AOF文件中;
文件同步:将内存缓冲区的数据写到磁盘;(由于OS的特性导致)
appendfsync选项:
always:每条写指令时都写到AOF文件;
everysec:将aof_buf中所有内容写到AOF文件,如果上次同步AOF文件时间距当前时间超过1s,那么对AOF文件同步;
no:由操作系统自动调度刷磁盘,性能是最好的。
持久化机制
因为bgsave会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。在redis实例重启时,会使用bgsave持久化文件重新构建内存,再使用aof重放近期的操作指令来实现完整恢复重启之前的状态。
两个关键词
Fork:不论是RDB还是AOF,都会fork一个子进程来做持久化(save命令除外,但是很少使用save命令,因为会阻塞redis服务器进程)
COW(copy on write):在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间。
https://www.shangmayuan.com/a/06f0cc3e38d04045808ab231.html
你的Redis怎么持久化的