1. 特点:
优点:
1 性能高:redis 速度 读:11万/s 写:8万/s
2 丰富的数据类型
3 原子性:操作时原子性的,意思是要么成功执行要么失败完全不执行,单个操作时原子性的(排队),多个操作也支持事务,通过MULTI EXEC指令包起来
- 支持持久化操作
4 其他功能:事务,发布订阅,通知,过期
缺点:
1 内存数据库,依赖于机器的内存大小
2 修改配置文件,重启等操作,需要将硬盘中的数据加载到内存,时间比较久。在这个过程中,redis不能提供服务
2. redis安装
- 下载redis包: wget http://download.redis.io/releases/redis-4.0.2.tar.gz
- tar -zxvf解压: tar xzf redis-4.0.2.tar.gz
- cd到解压目录: cd edis-4.0.2
- 执行make 完成编译
3. 启动停止
- 修改redis.conf相关配置
- 开启redis服务: redis-server ./redis.conf
- 停止redis: redis-cli shutdown(强行终止,redis进程可能会导致数据丢失,正确停止redis的发送shoutdown命令当redis收到shutdown命令后,会先断开所有所有客户端连接,然后根据配置执行持久化,最终完成退出)
- 远程连接: redis-cli -h host -p port -a password
4. redis核心配置文件redis.conf讲解文件
配置文件位于redis安装目录下 => redis.conf
- port 6379 //修改端口
- daemonize no => daemeonize yes //开启守护进程,会将pid将写入一个文件
- bind 127.0.0.1 //将其注释便可远程连接
- database 16 // 集群数量(默认是16)
- save <second> <changes> //指定多长时间内有多少次更新操作,就将数据同步>到磁盘.默认值如下
save 900 1 表示 900秒内有1个更改
save 300 10 表示 300秒有10个更改
save 60 10000 表示 60秒有10000个更改- dbfilename dump.rdb // 指定本地数据库的文件名
- requirepass pass // 是否需要密码访问
- maxclient //设置连接限制
- maxmemory <bytes> //内存最大限制
- slaveof ip port // 设置从服务的IP和端口
5. redis 原理分析
- redis是单线程
完全基于内存:因为redis是基于内存的操作,CPU不是redis的瓶颈,redis的瓶颈最有可能是机器内存的大小或网络带宽,竟然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程地方案
- 使用多路I/O复用模型
多路I/O复用模型利用select.poll,epoll可以调试检查多个流的I/O事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就会从阻塞状态中唤醒,于是程序就会轮询一遍所有的流(epoll是只轮询那些真正发出事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量无用的操作。这里的多路指的是多个网络连接。复用值得是复用同一个线程。简单来说就是有多少网络连接过来。我就只有一个线程处理,按顺序排队,当然处理速度是相当快,不会因为处理速度导致整个队列阻塞
6. redis的数据持久化
redis支持两种方式的持久化
- RDB(redis data base):内存数据快照根据指定的规则事件内将内存的数据存储在硬盘上,RDB保存的dump.rdb文件
触发方式有以下几种:
- 根据配置规则进行自动快照(例如:save 900 1 )
- 用户执行SAVE或者BGSAVE命令
- 执行flushall命令
- 执行复制 replication时
优点:
- 适合大规模的数据恢复
- 如果业务对数据完整性和一致性要求不高,RDB是很好的选择
缺点:
- 数据完整性和一致性不高,因为RDB可能在最后一次备份宕机了
- 备份时占用内存,因为redis会在备份时会独立创建一个子进程,将数据克隆一份,大致2倍的膨胀性需要考虑
- AOF(append-only-life):
以日志形式记录每个写操作。他的出现时为了弥补redis的不足,redis的重启会根据日志文件的内容将写指令从前往后执行一次以完成数据的恢复工作,AOF保存的是appendonly.aof文件
AOF的重写原理: Reid是可以在AOF的文件体积变得过大时,自动在后台对AOF进行重写,整个重写的过程并不是基于原有的aof的文件来做的,类似于快照的方式,全量遍历内存的数据,然后逐个序列到aof文件中。在fork子进程的这个过程中,服务端仍然对外提供服务,那这个时候重写的aof文件的数据和redis的内存数据不一致了怎么办?在这个过程中,主进程的数据更新操作,会缓存到aof_rewrite_buf中,也就是单独开辟一块缓存来存储重写期间收到的命令,当子进程重写完后没在吧缓存中的数据追加到新的aof文件,当所有的数据全部追加到新的aof文件中后,把新的aof文件重命名。此后所有的操作都会被写入到新的aof文件中
优点:
数据的完整性和一致性很高
缺点:
记录内容太多,文件就会越来越大,数据恢复也越来越满
总结
1 RDB 持久化方式能够在指定时间间隔对数据进行快照存储
2 AOF 持久化方式记录每次对服务器的写操作每当服务器重启时会重新执行这些命令来恢复原始数据,Redis还能对AOF文件进行后台重写,是的AOF文件的体积不至于过大
3 同时开启两种持久化方式
在这种情况下,当redis重启的时候会先载入AOF文件来恢复原始数据,因为通常情况下AOF问价保存的数据集比RDB文件保存的数据集要完整
那要不要只使用AOF呢?建议不要因为RDB更适合用于备份数据库,快速重启。
4 性能建议
因为RDB只用作后备用途,建议旨在slave上持久化RDB文件,而且只要15min备份一次就够了,只保留save 900 1 这条规则
如果enable AOF 好处是在最恶劣的情况下,丢失的数据也不超过2秒,启动问脚本只要load自己的AOF文件即可,代价是带来了持续的IO,另外AOF rewirte 过程中产生的新数据写到新文件造成的阻塞不可避免。只要硬盘愘,应该尽量减少AOF rewrite的频率,AOF重写的基础默认值64M太小,可以设置到5G以上,如果禁用 AOF,仅靠Master-Slave Replication实现高可用也可以,省掉一大笔IO也减少rewrite时带来的系统波动,代价时master/slave同时挂了,会丢失十几分钟的数据,启动脚本要比较两个Master/slave中RDB文件,载入比较新的那个
7 redis常用的数据类型
- 基本key操作
key pattern // 查看key,如key *
del key // 删除key
expire key time // 设置有效时间(单位秒)
ttl key // 查看key还有多少秒过期
type key // 查看key的类型
rename key newkey // 修改key的名称
exists key // 检查key的hi否存在
flushdb // 删除当前库所有的key
flushall // 删除所欲的库的key
- String
是redis最基础的数据类型,存储任何形式的字符串,包括二进制数据,一个字符类型允许存储的最大容量是512M
应用场景:
1.缓存:利用redis高并发特点,大大加快系统读写速度,以及降低后端数据库压力
2.计数器:实时计数器,可以快速实现技术和查询的功能。
3.共享用户session
4.事务锁,防止频繁操作、事务判断
利用一个字段用SETNX设置它的值,如
SETNX flag 1 60
这时flag不存在的话被设置为1,过期时间为60S,并返回1。如果flag已经存在,设置失败返回0(代表操作已经上锁)
set key value
get key
strlen key //获取value的长度
incr key // 将value值加1
incrby key step //将value值加step
decr key // 将value值减1
decrby key step // 将value值减step
append key str // 将value的值拼接上str
- Hash
应用场景:
缓存数据对象,便于条件查询
hset key field value
hmset key field1 value1 field2 value2 // 设置多个字段的值
hget key field
hgetall key
hmget key field1 field2 // 获取多个字段的值
hlen key // 获取字段的数量
hkeys key // 查看所有的字段
hdel key field // 删除某个字段
- List
应用场景:
1.缓存列表型的数据结构,类似文章评论,粉丝列表,实现分页查询
2.消息队列:redis的链表结构可以轻松的实现阻塞队列
列表内部使用双向链表实现,所以像列表两端添加元素的时间复杂度为O(1),获取越接近两端的元素速度就越快
rpush key value // 从尾部插入值
rpop key // 从尾部删除一个值
lpush key value
lpop key linsert key before|after 元素 要插入的值 // 指定元素父进插入值
lrange key start end // 查询指定范围的元素
lindex key index // 获取index位置的值
llen key // 获取列表的长度
lrem key num value // 删除num个值等于value的元素
lset key index value // 更新index位置的value值
- Set
集合类型在redis内部是使用空的散列表(hash table),所以这些操作的时间复杂度都是O(1)
应用场景:
- 去重
2.交集,并集,差集,比如运用来交集查询共同好友
sadd key value1 value2
smembers key // 查看所有元素
srem key value // 删除value的元素
scard key // 获取集合元素的数量
srandmember key count // 获取count个随机数(用于抽奖)
sinter key1 key2 // 获取俩集合的交集
sunion key1 key2 // 获取俩集合的并集
sdiff key1 key2 // 获取两集合的差集.以key1为准,key1有,key2没有
- Zset
应用场景:
1.排序。排行榜,如视频的排行榜(按照时间,播放量,获取的点赞数)
2.做带权重的队列,使队列有优先度的执行
zadd key1 score value
zrange key start end // 获取指定范围的元素(从小到大)
zrevrang key start end // 获取指定范围的袁术(从大到小)
zrank key value // 获取value的索引(从小到大)
zrevrank key value // 获取value的索引(从大到小)
zcard key // 获取元素的数量
zrem key value // 删除元素
- HyperLogLog
HyperLogLoh是用来做基数统计算法,优点是,在输入元素的数量或者体积非常非常大时,计算技术所需的空间总是固定的,并且是很小的。在redis里面,每个HyperLogLog 键只需要花费12kb内存,就可以计算接近2^64个不同的元素的基数,这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比
8. redis其他功能
发布订阅
使用场景:聊天室,公告牌,服务之间利用消息解耦
publish channel message //发布消息
subscribe channel // 订阅消息
unsubscribe channel //取消订阅
事务
一个队列,一次性,顺序的执行一系列命令(商品秒杀功能)
- 开始事务 multi
- 命令入队
- 执行事务 exec
不保证原子性,redis同一个事务这种如果有一条命令执行失败,其他命令仍然会被执行,没有回滚
另外如果采用redis cluster集群架构,不同的key有可能分配在不同的redis节点上,这种情况下redis的事务机制式不生效的,所以基本不用
redis数据淘汰机制
防止内存溢出的一种方法为设置过期值,但为了防止缓存穿透,缓存雪崩,需要设置不同的失效事件。
另外当redis所用内存达到上限时会促发内存回收机制,redis有6种内存回收策略,通过config set maxmemory-policy设置
noviction:默认,不删除任何数据,拒绝所有写入并返回错误
volatile-lru:根据lru删除设置了超时属性的键,直到腾出足够空间,如果没有可删的,使用noviction
allkeys-lru:根据lru删除数据,不管数据有没有设置超时的属性,直到腾出足够空间
allkeys-random:随机删除键,直到腾出足够的空间
volatile-random:随机删除过期键,直到腾出足够空间
volatile-ttl:根据键值对象的ttl谁能够,删除最近将要过去得到数据,如果没有,就用noeviction
缓存与数据库同步
使用对列,rabbitMq,kafaka等
集群
1 redis-cluster集群
redis3.0加上了cluster模式,实现redis的分布式存储,每台redis节点存储不同的内容。
redis-cluster采用无中心结构,
- 特点如下:
1 所有的节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽
2 节点的宕机时通过集群中超过半数的节点检测失效时才生效
3 客户端和redis节点直连,不需要之间代理层,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- 工作方式:
每一个节点上,都有一个插槽,当我们存取key的时候,redis会根据算法得出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,通过这个值,去找对应插槽所对应的节点,然后跳转到对应节点上进行存储操作。
为了保证高可用,redis-cluster 引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点,放其他主节点ping一个主节点A时,如果半数以上的主节点与A通信超时时,那么主节点A宕机了。如果主节点A和从节点都宕机了,那么集群就无法再提供服务了
- 优点:
1 可以进行水平扩容
2 无需哨兵监控,主节点宕机,redis cluster内部将从节点切换为主节点
3 支持自动化迁移,当某个从节点宕机,就只有主节点了,无法保证高可用性,这时候如果其他主节点有多余的从节点,集群自动把多余的从节点迁移到没有从节点的主节点中
- 缺点:
1 无法批量操作(mset,mget,keys等),因为不同的key会被划分到不同的节点,批量操作时行不通的。解决方式:(1) 如果key比较少,就用串行操作。(2)如果key很多,就使用hashtag保证key 映射到同一台节点上,如key为 {foo}:student1、{foo}:student2、 {foo}:student3,这类key一定实在同一个节点上,因为key中'{}'之间的字符串就是当前key的hash tags,只有{}当中的部分才被用来计算哈希槽。因此算出来的redis节点一定是同一个。
2 资源隔离性较差,容易出现互相影响的情况
3 无法事务,由于key可能分配再不同节点上,redis的事务机制是不生效的,另外redis事务不支持回滚操作,所以基本不用
缓存穿透
外部恶意攻击,例如用不存在的id频繁请求接口导致查询缓存不命中,然后击穿DB查询依然不命中,这时就会有大量请求穿透缓存访问到DB
- 解决
1 对不存在的用户,保存空对象进行标记,但会导致缓存中国存在大量无用的数据
2 使用BloomFilter过滤器
缓存击穿
某个热点数据失效时,大量针对这个数据的请求会穿透到数据源
1.针对多个热点key同时失效问题,可以在缓存时使用固定时间加上一个小的随机数避免大量的key同一时间失效
2.使用互斥锁更新,保证同一个进程针对同一个数据不会并发请求到DB,减小DB压力
缓存雪崩
缓存挂了,这是所有的请求都会穿透到DB
- 解决
1.使用快速熔断策略,减少DB瞬间压力
2.使用主从模式和集群模式来尽量保证缓存的高可用