美文网首页
Redis基础

Redis基础

作者: ands999 | 来源:发表于2019-09-28 17:19 被阅读0次
主从模式、网络分区、哨兵(主从切换)、持久化、复制(异步)、集群、哈希槽、rdb快照、aof日志、一致性、cap、过期、stream支持多播的可持久化的消息队列、lua脚本、pipeline批量发送命令、缓存雪崩、缓存穿透、缓存与数据库读写一致

Redis是REmote DIctionary Server的缩写。Redis可以保存键与5种不同类型的值之间的映射,持久化到硬盘,使用复制特性提高读性能,使用客户端分片提高写性能,使用集群提高写性能。是一个基于内存的高性能key-value内存数据库。

丰富的功能
  • 高性能: 支持约10万级别QPS
  • 持久化: 将内存中的数据保存到硬盘,保障数据安全,方便数据备份和恢复。
  • 缓存过期: 设置键的过期时间,在指定的时间之后自动被删除。expire、ttl。定期删除和惰性删除。
  • 复制: 提高服务可用性,分担读请求的负载。
  • Sentinel: 监控服务器状态,并在服务器发生故障时,自动故障转移。
  • 分布式集群Cluster: 创建分布式数据库,每个服务器分别执行部分写操作和读操作。
  • 客户端分片
  • 事务: 事务中多个指令一起是原子地执行,并提供乐观锁功能,保证处理数据时的安全性。需要指令是无相关性。执行过程中出现错误,也会继续执行。无法回滚。
  • Lua脚本: 在服务器端原子地执行多个操作,并减少客户端与服务器之间的通信往返次数。执行过程中出现错误,也会继续执行。无法回滚。
  • 订阅与发布: 将消息同时分发给多个客户端,用于构建广播系统。
  • Pipeline: 管道化,把多个命令一次性传输给服务器。将多次IO往返的时间缩减为一次,pipeline执行的指令之间没有因果相关性。
  • Stream: 支持多播的可持久化消息队列。
Pipeline

redis是cs模式的tcp server,使用和http类似的请求响应协议。client可以通过socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完请求命令后会将结果通过响应报文返回给client。
可以利用pipeline的方式在client打包多条命令一起发出,不需要等待单条命令的响应返回,而redis服务端处理完多条命令后会将多条命令的处理结果打包到一起返回给客户端。
假设不会因为tcp 报文过长而被拆分。通过pipeline方式可以节省浪费在网络延迟的时间。需要注意的是,用 pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。所以并不是打包的命令越多越好。

pub/sub

发布订阅(pub/sub)是一种消息通信模式,主要是解耦消息的发布者和订阅者之间的耦合,这和观察者模式比较相似。
订阅者通过subscribe或psubscribe命令订阅自己感兴趣的消息类型,redis将消息类型称为通道(channel)。当发布者通过publish命令发送特定类型的消息时。订阅该消息类型的全部client都会收到此消息。这里消息的传递是多对多。
使用psubscribe命令订阅多个通配符通道,如果一个消息匹配上了多个通道模式的话,会多次收到同一个消息。

tips
  • redis支持对list,set和sorted set元素的排序。
  • 定期通过异步方式把数据flush到硬盘上进行保存。
  • lettuce和jedis都是redis的客户端。
  • 事件轮询(多路复用)
  • RESP协议。相对于数据库逻辑来说,网络不会成为性能瓶颈。所以使用文本协议,简单。
  • pub/sub 实现消息的多播。一个生产者,多个消费者。
  • Redis的主要缺点是数据库容量受物理内存的限制。不支持事务回滚。集群出现网络分区时,只能支持AP。
  • Redis为了达到最快的读写速度而将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。
高性能原因
  • 基于内存
  • 数据结构简单,大部分操作的算法复杂度O(1)或者O(logn)。
  • 单线程,不用上下文切换。
  • 使用多路复用非阻塞模型(Reactor)
  • 自定义vm,不会一个value变化后就影响page cache。
分布式锁

setnx 会有死锁风险。再加上过期时间。但加锁和设置过期时间不是原子性,所以还是有死锁风险。
从2.8版本开始,set key value ex x nx。但还是会因业务逻辑执行时间较长,导致超时风险。这时需要人工介入。
这种分布式锁要支持锁的可重入性,需要在客户端的set方法进行封装,使用线程的Threadlocal变量存储当前持有锁的计数。精确一点,还要考虑内存锁计数的过期时间。锁的可重入性导致逻辑复杂度提升非常高。因此建议通过改变代码的逻辑结构避免锁的重入。

独特的键值对模型

很多数据库只能处理一种数据结构:
• SQL 数据库 —— 表格
• Memcached —— 键值缓存,键和值都是字符串
• 文档数据库(MongoDB) ——由 JSON/BSON 组成的文档(document)
Redis 的值有五种数据结构。

redis比memcached快

猜测有下面几个原因

  • Libevent。和Memcached不同,Redis并没有选择libevent。Libevent为了迎合通用性造成代码庞大及牺牲了在特定平台的不少性能。Redis用libevent中两个文件修改实现了自己的epoll event loop。业界不少开发者也建议Redis使用另外一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行./configure。
  • CAS问题。CAS是Memcached中防止竞争修改资源的方法。CAS实现需要为每个cache key设置一个隐藏的cas token,cas相当value版本号,每次set,token需要递增,因此带来CPU和内存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及QPS上万之后这些开销就会给双方相对带来一些细微性能差别。

相关文章

网友评论

      本文标题:Redis基础

      本文链接:https://www.haomeiwen.com/subject/ycluyctx.html