Redis简述

目录

Redis

Memcached 和redis对比

缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题

一、缓存雪崩

二、缓存穿透

三、缓存预热

四、缓存更新

五、缓存降级


Redis

Redis是一个开源的,基于键值对(key-value)的数据结构存储系统,它可以用作数据库、缓存和消息代理。Redis以其高性能、低延迟和丰富的数据结构特性而著称,广泛应用于各种场景,特别是那些需要快速读写操作和高可扩展性的应用中。以下是Redis的一些核心特点和功能:

1.数据结构丰富:Redis不仅仅支持简单的字符串键值对,还提供了列表(Lists)、集合(Sets)、有序集合(Sorted Sets)、哈希表(Hashes)等多种数据结构,以及位图(Bitmaps)、超日志(HyperLogLogs)和地理空间索引(Geospatial Indexes)等高级数据类型。

  1. 位图(Bitmaps): 位图是一种紧凑的数据结构,用于将一个大的数字集合表示为一系列比特位。每个比特位代表集合中的一个元素,值为1表示该元素存在,值为0表示不存在。位图非常适合于统计、去重计数、简单的布尔操作等场景,如用户活跃度跟踪、布隆过滤器等。Redis提供了对位图的一系列操作,如设置、获取比特位、按位运算等。

  2. 超日志(HyperLogLogs): HyperLogLog是一种概率型数据结构,用于估算集合的唯一元素数量(基数)。它能够在极小的空间占用下,非常精确地估计出一个集合中不重复元素的数量,误差率极低。HyperLogLog特别适用于需要频繁合并计数、但不需要精确计数的场景,如网站的UV(独立访客)统计。Redis中的HyperLogLog命令允许添加元素、合并多个HyperLogLogs以及计算估计的基数。

  3. 地理空间索引(Geospatial Indexes): Redis支持地理空间数据类型和相关操作,允许用户存储地理位置信息(经度和纬度坐标),并对这些位置数据执行诸如查找附近位置、计算两点间距离等操作。Redis使用了GeoHash算法来实现地理空间索引,支持两种地理空间数据结构:GEOHASH(用于存储位置的编码)和GEO(直接存储坐标对)。通过GEOADDGEOPOSGEODISTGEORADIUSGEORADIUSBYMEMBER等命令,可以轻松实现基于地理位置的服务,如查找附近的餐厅、店铺等。

这些高级数据结构极大地扩展了Redis的应用范围,使其不仅限于简单的键值存储,还能高效处理复杂的数据分析和空间查询任务,非常高效且节省空间。

2.持久化:Redis提供了两种主要的持久化方式,RDB(快照)和AOF(Append Only File),以便在服务器重启后恢复数据状态。RDB通过定期保存数据库的快照来实现持久化AOF则记录所有写操作命令,数据恢复时重新执行这些命令以达到重建数据的目的。

实现: 单独创建 fork() 一个子进程,将当前父进程的数据库数据复制到子进程的内存中,然后由子进程写入到临时文件中,持久化的过程结束了,再用这个临时文件替换上次的快照文件,然后子进程退出,内存释放。
RDB是Redis默认的持久化方式 是指用数据集快照的方式半持久化模式 ) 记录 redis 数据库的所有键值对 , 在某个时间点将数据写入一 个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
优点:
1 、只有一个文件 dump.rdb ,方便持久化。
2 、容灾性好,一个文件可以保存到安全的磁盘。
3 、性能最大化, fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任
IO 操作,保证了 redis 的高性能 ) 4. 相对于数据集大时,比 AOF 的启动效率更高。
缺点:
1 、数据安全性低。 RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不
严谨的时候 )
AOF: 是指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储 ) 保存为 aof 文件。Redis会将每一个收到的写命令都通过 Write 函数追加到文件最后,类似于 MySQL binlog 。当 Redis 重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
优点:
1 、数据安全, aof 持久化可以配置 appendfsync 属性,有 always ,每进行一次命令操作就记录到 aof 文件中一次。
2 、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。
3 AOF 机制的 rewrite 模式。 AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall )
缺点:
1 AOF 文件比 RDB 文件大,且恢复速度慢。
2 、数据集大的时候,比 rdb 启动效率低。
当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复

3.高可用性:Redis支持主从复制(Master-Slave Replication),可以配置多个从节点来提高系统的读取能力和容错性。此外,Redis Cluster提供了自动分割数据到多个节点的能力,实现了水平扩展和故障转移

4.发布/订阅(Pub/Sub):Redis支持发布/订阅模式,可以作为一个简单而高效的轻量级消息代理,用于实现消息队列、实时通知等功能。

5.Lua脚本:Redis允许用户在服务器端执行Lua脚本,这样可以在单个操作中执行复杂的逻辑,减少网络往返时间并提高效率。

Lua脚本是Redis中的一项重要功能,它允许用户在Redis服务器端执行Lua代码,以实现更复杂的逻辑操作。Lua是一种轻量级的脚本语言,以其简洁高效著称,非常适合嵌入到应用程序中执行高性能的任务。在Redis中使用Lua脚本有以下几个显著优点:

  1. 原子性操作:执行Lua脚本时,Redis会将整个脚本作为一次性操作处理,这意味着脚本内的所有命令会在服务器端顺序执行,中间不会被其他客户端的请求打断,保证了操作的原子性。

  2. 减少网络开销:通过在服务器端执行一系列命令,而不是客户端逐一发送命令,可以显著减少客户端与服务器之间的网络通信次数,提高执行效率。

  3. 灵活性和复杂性:Lua脚本支持循环、条件判断、函数调用等编程结构,使得开发者可以实现比单纯使用Redis命令更复杂的逻辑操作,比如事务、条件更新等。

  4. 缓存和复用:Redis可以将Lua脚本缓存起来,后续执行相同脚本时只需通过脚本的SHA-1散列值引用即可,避免了重复传输脚本内容,进一步提升了效率。

使用Lua脚本的基本步骤包括:

  • 编写脚本:在Lua语言中编写脚本,脚本中可以使用redis.call()redis.pcall()函数来调用Redis命令。

  • 发送脚本到Redis:可以通过EVAL命令直接发送脚本到Redis服务器执行,并立即得到结果。对于重复使用的脚本,可以先使用SCRIPT LOAD命令加载脚本到Redis并获取其SHA-1散列值,后续使用EVALSHA命令通过散列值执行脚本。

示例Lua脚本:

-- 增加两个键的值并将结果存储在第三个键中
local key1 = KEYS[1]
local key2 = KEYS[2]
local destKey = KEYS[3]

local val1 = redis.call('GET', key1)
local val2 = redis.call('GET', key2)

if not val1 or not val2 then
    return nil -- 如果任何一个键不存在,返回nil
end

local sum = tonumber(val1) + tonumber(val2)
redis.call('SET', destKey, sum)

return sum

这段脚本可以使用EVAL命令配合相应的键名数组和无参数数组发送给Redis执行。Lua脚本的引入,使得Redis能够处理更多样化的数据处理需求,特别是在需要复杂逻辑处理的场景下。

6.内存存储与磁盘备份:虽然Redis主要将数据存储在内存中以实现高速访问,但它也提供了机制来将数据定期持久化到磁盘上,以防止数据丢失。

Redis因其灵活性和高性能,常被用于会话缓存、全页缓存、实时分析、排行榜、消息队列、分布式锁等应用场景。

Memcached 和redis对比

Memcached 和 Redis 是两种广泛使用的内存数据存储系统,主要用于缓存和提升数据访问速度。下面是它们之间的一些关键对比:

1.数据结构:

  • Memcached: 主要支持简单的键值对存储,其中键和值都是字符串形式。
  • Redis: 支持更丰富的数据结构,包括字符串、列表、集合、有序集合、哈希表等,这使得Redis能更好地适应多种数据存储和操作需求。

2.集群模式:

  • Memcached: 原生不支持集群,需要客户端实现数据的分片和路由,或者借助第三方工具实现集群。
  • Redis: 原生支持集群模式(Redis Cluster),能够自动进行数据分片和故障转移。

3.性能:

  • 在处理小规模数据时,Redis的性能通常优于Memcached,因为Redis优化了内存使用和数据结构。
  • 当数据大小超过一定阈值(通常为100KB以上),Memcached在读写速度上可能更占优势,因为它设计更简单,专为大块数据缓存优化。

4.线程模型:

  • Memcached: 采用多线程模型,能够充分利用多核CPU资源。
  • Redis: 早期版本主要采用单线程模型处理客户端请求,但I/O和后台操作(如持久化)可以是多线程的。新版本Redis也引入了多线程IO来进一步提升性能。

5.持久化:

  • Memcached: 不支持数据持久化,数据仅存储在内存中,服务器重启后数据丢失。
  • Redis: 支持数据持久化,可通过RDB(快照)和AOF(日志)机制将数据保存到磁盘。

6.复制:

  • Memcached: 不原生支持数据复制。
  • Redis: 支持主从复制,可以配置多个从节点提高系统的可用性和读取能力。

7.内存管理:

  • Memcached的内存使用效率较高,尤其在存储简单的键值对时。
  • Redis提供了更复杂的内存管理策略,如数据压缩(如在哈希结构中),但这也可能导致更高的内存占用。

8.安全性:

  • Redis提供了认证机制,支持密码保护。
  • Memcached传统上没有内置安全机制,但现代部署可能会通过网络隔离或其他安全措施来弥补。

        总的来说,Memcached更适合于简单的、大规模的缓存场景,特别是当数据结构简单且不需要持久化时。而Redis则因为其丰富的数据结构、持久化能力、集群支持和更广泛的用途(如消息队列、实时分析等),适合于需要更复杂数据操作和更高要求的场景。选择哪一种取决于具体的应用需求、数据模型以及对性能、持久性、灵活性的要求。

缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题

一、缓存雪崩

        简单的理解为:由于原有缓存失效,新缓存未到期间( 例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期) ,所有原本应该访问缓存的请求都去查询数据库了,而对数据库 CPU 和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
解决办法:
        大多数系统设计者考虑 用加锁( 最多的解决方案)或者队列 的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。
        还有一个简单方案就是将 缓存失效时间分散开

二、缓存穿透

        缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。
解决办法 ;
        最常见的则是采用 布隆过滤器 ,将所有可能存在的数据哈希到一个足够大的bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。
        另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。
5TB 的硬盘上放满了数据,请写一个算法将这些数据进行排重。如果这些数据是一些 32bit 大小的数据该如何解决?如果是 64bit 的呢?
        对于空间的利用到达了一种极致,那就是Bitmap 和布隆过滤器 (Bloom Filter)
Bitmap : 典型的就是哈希表
         缺点是,Bitmap对于每个元素只能记录 1bit 信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空间、时间来完成了
布隆过滤器(推荐)
就是引入了 k(k>1)k(k>1) 个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过程。
优点 是空间效率和查询时间都远远超过一般的算法, 缺点 是有一定的误识别率和删除困难。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
        Hash存在一个冲突(碰撞)的问题,用同一个 Hash 得到的两个 URL 的值有可能相同。为了减少冲突,我们可以多引入几个 Hash ,如果通过其中的一个Hash 值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的 Hash 函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是Bloom-Filter 的基本思想。
         Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。

三、缓存预热

        缓存预热这个应该是一个比较常见的概念,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!
        用户直接查询事先被预热的缓存数据!
解决思路:
  1. 直接写个缓存刷新页面,上线时手工操作下;
  2. 数据量不大,可以在项目启动的时候自动进行加载;
  3. 定时刷新缓存

四、缓存更新

        除了缓存服务器自带的缓存失效策略之外(Redis 默认的有 6 中策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:
  • 定时去清理过期的缓存;
  • 当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。
两者各有优劣,第一种的缺点是维护大量缓存的 key 是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡

五、缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
降级的最终目的是保证核心服务可用 ,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。
以参考日志级别设置预案:
  1. 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
  2. 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;
  3. 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
  4. 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查 询,而是直接返回默认值给用户

相关推荐

  1. Redis简述

    2024-05-13 16:16:02       29 阅读
  2. 简述redis事务

    2024-05-13 16:16:02       31 阅读
  3. Redis 简介

    2024-05-13 16:16:02       60 阅读
  4. Redis 简介

    2024-05-13 16:16:02       54 阅读
  5. redis简介

    2024-05-13 16:16:02       40 阅读
  6. Redis简介

    2024-05-13 16:16:02       30 阅读
  7. redis简介

    2024-05-13 16:16:02       37 阅读
  8. Redis简介

    2024-05-13 16:16:02       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-13 16:16:02       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-13 16:16:02       107 阅读
  3. 在Django里面运行非项目文件

    2024-05-13 16:16:02       90 阅读
  4. Python语言-面向对象

    2024-05-13 16:16:02       98 阅读

热门阅读

  1. linux下sd卡的备份与还原

    2024-05-13 16:16:02       31 阅读
  2. 动态NAT

    动态NAT

    2024-05-13 16:16:02      34 阅读
  3. 猜数字(c++语言)

    2024-05-13 16:16:02       32 阅读
  4. 为什么数据库字符编码不一致会导致索引失效

    2024-05-13 16:16:02       32 阅读
  5. 【Git LFS】Git管理大文件

    2024-05-13 16:16:02       34 阅读
  6. lustre文件系统详细介绍

    2024-05-13 16:16:02       31 阅读
  7. Python基础学习之datetime模块

    2024-05-13 16:16:02       34 阅读
  8. Electron Forge | 跨平台实战详解(中)

    2024-05-13 16:16:02       32 阅读