在讲redis之前,我们先来简单的了解NoSql
NoSql:
优点: 去掉了关系数据库的"关系特性" ,易扩展 ,有非常高的读写性能 尤其大数据量下,灵活的数据模型(无需提前建立字段) 缺点: 没有统一的标准 层出不穷
四大分类:
一、键值对存储 =>redis 优势:查找速度比较快 劣势:存储数据缺少结构化
二、列存储 优势:查找速度比较快 扩展性强 劣势:功能比较局限性
三、文档数据库 =>MongoDB 优势:数据结构要求不严格 劣势:查询性能不是特别的高
四、图形数据库 =>应用于社交网络的数据库 优势:图结构的算法 劣势:不容易分布式集群方案
而redis则隶属于NoSql的第一分类,键值对存储
Redis(c语言编写、key-value形式存储):
特点:
Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave(读写分离,增删改由master服务器完成、查询由slave服务器完成)模式的数据备份。
Redis还支持一些特殊数据结构,如:BitMaps(位图), HyperLogLog(超小内存唯一值计数),GEO(地理信息定位)等。
优势:
性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
现在让我们来看看redis的5种基本数据结构和基本操作命令。
String:
设置值 | set key value | 获取值 | get key | 重新设值,并返回旧的值 | getset key value |
设置过期时间 | setex key 1000 value | key 不存在时设置值 | setnx key value | 返回值长度 | strlen key |
数字 增减 | incr key/decrkey | 增加5 | incrby key 5 | 减5 | decrby key 5 |
Hash:
设置值 | hset 名称 键 值 | 多设置 | hmset 名称 键 值 键 值 ... | 获取 | hget 名称 键 |
多获取 | hmget 名称 键 键 ... | 删除 | hdel 名称 键... | 键值对数量 | hlen 名称 |
取所有键 | hkeys 名称 | 取所有值 | hvals 名称 | 是否存在 | hexists 名称 |
List:
左插入 | lpush 列名 [值..] | 右插入 | rpush 列名 [值..] | 查询 | lrange 列名 [begin,end] |
左移除 | lpop 列名 | 右移除 | rpop 列名 | 数量 | llen 列名 |
已有列左插入 | lpushx 列名 [值...] | 已有列右插入 | rpushx 列名 [值...] | 移除 | lrem 列名 [count] 值 |
指定插入 | lset 列名 [index] 值 | 插入指定值前 | linsert 列名 before [指定值] 值 | 插入指定值后 | linsert 列名 after [指定值] 值 |
Set:
设置值 | sadd 列名 [值...] | 删 | srem 列名 [值...] | 查整列 | smembers 列名 |
是否存在 | sismember 列名 值 | 差集 | sdiff 列名1 列名2 | 并集 | sunion 列名1 列名2 |
数量 | scard 列名 | 随机查 | srandmember 列名 | 将差集存到新集合中 | sdiffstore 新列名 列名1 列名2 |
将交集存到新集合中 | sinterstore 新列名 列名1 列名2 | 将并集存到新集合中 | sunionstore 新列名 列名1 列名2 |
zset:可排序的set,它增加了一个顺序属性字段,用来存顺序编号(所有的指令后面都可追加withscores命令来显示元素编号)
添加 | zadd key 顺序编号 值 | 删除 | zrem key 值 | 返回指定元素的排名(从小到大) | zrank key 值 |
返回指定元素的排名(从大到小) | zrevrank key 值 | 返回多个元素的排名(从小到大) | zrange key 索引1 索引2 | 返回多个元素的排名(从大到小) | zrevrange key 索引1 索引2 |
返回集合的数量 | zcard key |
Keys的通用操作:
所有键列 | keys * | 指定开头键列 | keys [*]? | 删 | del 键 |
判断存在 | exists 键 | 重命名 | rename 旧键名 新键名 | 设过期时间 | expire 键 1000 |
查过期时间 | ttl 键 | 键的值类型 | type 键 |
redis还支持事务及回滚的功能。
事务:开始事务:执行mukit开启事务 、命令入队:增删改命令 、执行事务: exec后,事务提交,命令会一起执行。
回滚:执行mukit命令后,set username zhangsan ,然后执行discard,那么set将不会执行。
此外,redis还存在持久化的概念。
什么是持久化:redis所有数据保存在内存中,同时在硬盘中还存储一份。
持久化方式:
快照:MySQL dump 、Redis RDB。
写日志:MySQL binlog、Hbase HLog、Redis AOF。这里我们来了解redis的持久化。
持久化的触发方式主要有三种:save(同步)、bgsave(异步)、自动
第一种:直接执行save命令。创建了RDB文件(二进制),但是是同步的,数据较大时,会造成阻塞。如果存在老的RDB文件,将会替换
第二种:直接执行bgsave命令。异步的,由子进程来完成,完成后会返回状态给主进程。但是需要fork(创建子进程),消耗内存
第三种:自动的,有以下两种方式1、RDB (内存快照):默认支持,不需要配置,会在硬盘创建一个RDB的二进制文件,在指定的时间间隔将数据快照写入文件,同时redis重启时会载入这个文件。
优点:
(1) 数据库只包含一个文件,通过文件备份策略,定期配置,恢复系统灾难。
(2) 压缩文件转移到其他介质上。
(3) 性能最大化,redis开始持久化时,分叉出进程,由子进程完成持久化的工作避免服务器进程执行I/O操作,启动效率高。
缺点:
(1)无法高可用:系统一定在定时持久化之前宕机,数据还没写入,数据已经丢失。
(2)通过fock分叉子进程完成工作,数据集大的时候,服务器需要停止几百毫秒甚至1秒。2、AOF(命令日志):需要配置开启,将以日志的形式,记录每一个增删的操作,服务器启动后,读取那个日志,执行记录的操作,构建数据库。
优点:
(1) 同步写入,频率高,效率低,方式最安全。.
(2) 写入模式采用append模式,追加模式, 不破坏写入日志数据,在redis中追加也不会破坏文件.如果在写入一半时候就出现崩溃问题,redis下次启动之前通过 redis-check-aof这个工具来帮助数据一致性问题。
(3) 当数据过大,可启动修改重写机制,redis采用append的这种机制,将新的修改的数据不断的写到老的磁盘文件当中,同时创建新的文件保存操作,保证修改数据的更新。
(4) 日志文件格式清晰,便于重建数据。
(5) 会将一些命令进行优化:如对同一个值进行多次set,那么AOF只会保留最后一次的set。
缺点:
(1) 对于相同数据集aof文件比rdb文件大一些。
(2) 根据同步策略不同,效率比rbd低.。同步策略:
appendfsync always 每修改一次就同步到磁盘上。不丢失数据,但IO开销较大
appendfsync everysec 每秒会向硬盘中同步一次(默认值)。可能会丢失一秒的数据
appendfsync no 不会主动调将AOF日志内容同步到磁盘,完全依赖于操作系统,大多数Linux操作系统,是每30秒将数据写入磁盘。二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。
redis的fork操作问题
同步操作,当fork时间过长时,会造成主线程的阻塞,redis内存越大,耗时越长(与机器类型有关,(虚拟机和物理机))
info:latest_fork_usec 查询持久化的时间,上一次执行fork的微秒数
改善fork:
1、优先使用物理机或者高效支持fork操作的虚拟化技术。
2、控制Redis实例最大可用内存:maxmemory
3、合理配置Linux内存分配策略:vm.overcommit_memory
4、降低fork频率:例如放宽AOF重写自动触发时时机,不必要的全量复制。
(vm.overcommit_memory = 1。默认是0,如果刚好要进行fork的话,fork就会阻塞。
0:表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
1: 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
2: 表示内核允许分配超过所有物理内存和交换空间总和的内存)
redis的过期策略都有哪些?内存淘汰机制都有哪些?
(1) 定期删除+惰性删除:所谓定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。但是问题是,定期删除可能会导致很多过期key到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。
(2) 如果redis的内存占用过多的时候,此时会进行内存淘汰,有如下一些策略:
- noeviction:当内存不足以容纳新写入数据时,新写入操作会报错
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key.
- volatile-lru:在设置了过期时间的键空间中,移除最近最少使用的key
- volatile-random:在设置了过期时间的键空间中,随机移除某个key
- volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰、
使用策略规则:
1、如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用allkeys-lru
2、如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-rando
单线程的redis为什么这么快
(1)纯内存操作
(2)核心是基于非阻塞的IO多路复用机制
(3)单线程反而避免了多线程的频繁上下文切换问题
redis的其它特性
主从复制:
是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数据库一般是实时的业务数据库,从数据库的作用和使用场合一般有几个:
一是作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作;
二是可在从数据库作备份、数据统计等工作,这样不影响主数据库的性能;
虚拟内存(2.6以后不再支持):
Redis中的虚拟内存和Linux中的虚拟内存不是一回事,但是其思想是一致的,就是把暂时不常用的数据从内存交换到磁盘中,从而可以把宝贵的内存腾出来用于其他需要访问的数据,尤其是像Redis这样的内存数据库,内存的数量无意会成为一个瓶颈。虽然我们可以把数据分割到多个服务器上,但是虚拟内存依然是一个相当有效的解决办法。当你的key很小而value很大时,使用VM的效果会比较好。因为这样节约的内存比较大,当你的key不小时,可以考虑使用一些非常方法将很大的key变成很大的value,比如你可以考虑将key,value组合成一个新的value。vm-max-threads这个参数,可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟,但是对数据完整性有很好的保证。Redis的数据全部放在内存带来了高速的性能,但是也带来一些不合理之处。比如一个中型网站有100万注册用户,如果这些资料要用Redis来存储,内存的容量必须能够容纳这100万用户。但是业务实际情况是100万用户只有5万活跃用户,1周来访问过1次的也只有15万用户,因此全部100万用户的数据都放在内存有不合理之处,RAM需要为冷数据买单。这跟操作系统非常相似,操作系统所有应用访问的数据都在内存,但是如果物理内存容纳不下新的数据,操作系统会智能将部分长期没有访问的数据交换到磁盘,为新的应用留出空间。现代操作系统给应用提供的并不是物理内存,而是虚拟内存(Virtual Memory)的概念。
慢查询(慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(慢查询ID,发生时间戳,耗时,命令的详细信息)记录下来,放入一个先进先出的队列)
- 生命周期:发送命令、命令需排队、执行命令、返回结果。
- 慢查询发生在第三阶段、客户端超时不一定慢查询,但慢查询是客户端超时的一个因素
- slowlog-log-slower-than:预设阀值,单位是微秒,默认值是10000,如果一条命令的执行时间超过10000微妙,那么它将被记录在慢查询日志中。0是记录所有,小于0不会记录任何命令
- slowlog-max-len表示慢查询日志最多存储多少条。Redis使用一个列表来存储慢查询日志,slowlog-max-len就是列表的最大长度。当慢查询日志已经到达列表的最大长度时,又有慢查询日志要进入列表,则最早插入列表的日志将会被移出列表,新日志被插入列表的末尾。
- 获取慢查询日志slowlog get [n](长度)、获取慢查询日志列表的当前长度slowlog len、慢查询日志重置slowlog reset(清空列表)
(1)slowlog-max-len的设置建议
线上环境建议调大慢查询日志的列表,记录慢查询日志时Redis会对长命令做截断操作,并不会占用大量内存。增大慢查询列表可以减缓慢查询被剔除出列表的可能性。例如线上可以设置为1000以上。
(2)slowlog-log-lower-than的设置建议
需要根据redis的并发量调整该值。由于redis采用单线程响应命令,对于高流量的场景,如果执行命令的时间在1毫秒以上,那么redis最多可支撑OPS(每秒操作次数)不到1000,因此高OPS场景的REDIS建议设置为1毫秒。
(3)慢查询只记录命令执行时间,并不包括命令排队时间和网络传输时间。因此客户端命令的执行时间要大于redis服务器实际执行命令的时间。因为命令执行排队极致,慢查询会导致命令级联阻塞,因此当客户端出现请求超时,需要检查该时间点是否有对应的慢查询,从而分析是否因为慢查询导致的命令级联阻塞
(4)慢查询日志是一个先进先出队列,慢查询较多的情况下,可能会丢失部分慢查询命令,可以定期执行slow get命令将慢查询日志持久化到其他存储中。然后制作可视化界面查询。
pipeline(流水线)
当我们客户端向redis发送一条命令时,会经过网络传输,然后到达redis执行命令返回结果。多个命令就要经过多次网络传输。
而流水线可以一次向redis发送多条命令,这样只会经过一次网络传输。
发布订阅
发布者、订阅者、频道
发布者向某个频道发布消息,订阅者订阅了这个频道,然后接受到了消息。后订阅者无法收到之前的发布消息。
以上先暂时到这,如有错误,请及时指出,本人感激不尽。