<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="https://blog.anlucky.cn/index.php/feed/rss/tag/%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE%E5%BA%93/">
<title>LuckyDu - 缓存数据库</title>
<link>https://blog.anlucky.cn/index.php/tag/%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE%E5%BA%93/</link>
<description></description>
<items>
<rdf:Seq>
<rdf:li resource="https://blog.anlucky.cn/index.php/programming/database/152"/>
<rdf:li resource="https://blog.anlucky.cn/index.php/programming/database/147"/>
</rdf:Seq>
</items>
</channel>
<item rdf:about="https://blog.anlucky.cn/index.php/programming/database/152">
<title>缓存穿透，缓存击穿，缓存雪崩是什么如何解决</title>
<link>https://blog.anlucky.cn/index.php/programming/database/152</link>
<dc:date>2023-05-23T20:26:11+08:00</dc:date>
<description>1. 什么是缓存穿透缓存穿透指的是一个缓存系统无法缓存某个查询的数据，从而导致这个查询每一次都要访问数据库个人理解，缓存穿透是指要访问的数据既不在缓存中，也不在数据库中，导致请求在访问缓存时没有找到对应的数据，再去请求数据库也没有找到数据，无法将数据写入缓存，这样一来缓存就变为了摆设，就会同时给缓存和数据库造成压力常见的Redis缓存穿透场景包括：查询一个不存在的数据，攻击者可能发送一些无效的查询来触发缓存穿透查询一些非常热门的数据，如果一个数据被访问的非常频繁，那么可能会导致缓存系统无法处理这些请求，从而造成缓存穿透查询一些异常数据：这种情况通常发生在数据服务出现故障或异常时，从而造成缓存系统无法访问相关数据，从而导致缓存穿透。2. 如何解决缓存穿透解决方案一缓存空值或者缺省的值一旦发生缓存穿透，我们就可以针对查询的数据，再Redis中缓存一个空值或者确定的缺省值，（就是随便一个可以表示缺省的值），紧接着，发送后续的查询的时候就可以从缓存中获取到缺省值了，保证了数据库的正常运行解决方案二使用布隆过滤器快速判断数据是否存在3. 什么是缓存击穿缓存击穿往往出现在高并发访问的情况下，一个热点数据从缓存在查不存在，就要去数据库中查询，从而导致数据库的压力过大，导致系统性能下降缓存击穿的原因通常有以下几种：缓存中不存在所需要的热点数据，每当系统中的某个热点数据需要频繁访问的时候，同时去访问数据库，给数据库造负担缓存热点的数据过期，当一个热点数据过期，并且需要重新缓存时候，若此时有大量请求也会因为缓存中的数据过期而去数据库中查询，给数据库造成负担。4. 如何解决缓存击穿解决方案一设置热点数据永不过期设置热点数据永不过期就是不给key设置过期的时间即可还有第二种方式也可以达到key值永不过期，就是正常的给key值设置过期时间，在后台启动一个定时任务在他过期前去定时地更新这个缓存，并重新设置他的过期时间解决方案二分布式锁并发更新锁的对象就是key，这样如果有大量请求并发进来时，只能有一个请求获取到锁，然后获取到锁的线程去查询数据库，将查询到的数据放入到缓存中，此时，缓存中已经有数据了，后面的请求就可以从缓存中获取到数据返回，并不会查询数据库5. 什么是缓存雪崩缓存雪崩是指大量的请求无法在Redis中进行处理，紧接着大量的请求发送到数据库层，导致数据库压力过大常见的缓存雪崩的场景：缓存服务器宕机，当缓存服务器宕机或者重启时，大量的访问请求直接命中数据库，在同一时间导致大量的数据查询，从而数据库的压力增大缓存数据同时失效，在某个特定的时间点，缓存中的数据大量失效，并在同一个时间点，有大量的请求集中在一起6. 如何解决缓存雪崩解决方案一避免给大量的数据设置相同的过期时间，如果业务层有些数据同时失效，可以给每个数据设置一个较短的过期间隔，(在不影响业务的情况下，特殊情况特殊处理)解决方案二缓存预热缓存预热就是在系统启动或者失效时，手动加载数据到缓存中，这样实际请求的时候就可以直接从缓存中获取数据</description>
</item>
<item rdf:about="https://blog.anlucky.cn/index.php/programming/database/147">
<title>Redis基础入门</title>
<link>https://blog.anlucky.cn/index.php/programming/database/147</link>
<dc:date>2023-05-15T19:12:00+08:00</dc:date>
<description>Redis基础入门0.为什么Redis是单线程还这么快？redis 是将所有的数据全部放在内存中的，所以说使用单线程去操作效率就是最高的，多线程 （CPU上下文会切换：耗时的操作！！！），对于内存系统来说，如果没有上下文切换效率就是最高 的！多次读写都是在一个CPU上的，在内存情况下，这个就是最佳的方案！1. Redis介绍Redis 是一个开源（BSD许可）的，内存中的数据结构存储系统，它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构，如 字符串（strings）， 散列（hashes）， 列表（lists）， 集合（sets）， 有序集合（sorted sets） 与范围查询， bitmaps， hyperloglogs 和 地理空间（geospatial） 索引半径查询。 Redis 内置了 复制（replication），LUA脚本（Lua scripting）， LRU驱动事件（LRU eviction），事务（transactions） 和不同级别的 磁盘持久化（persistence）， 并通过 Redis哨兵（Sentinel）和自动 分区（Cluster）提供高可用性（high availability）。2. 关系型数据库和非关系型数据库关系型数据库（RDBMS）：表格 ，行 ，列泛指非关系型数据库的，随着web2.0互联网的诞生！传统的关系型数据库很难对付web2.0时代！尤其
是超大规模的高并发的社区！
暴露出来很多难以克服的问题，NoSQL在当今大数据环境下发展的十分迅速，Redis是发展最快的，而
且是我们当下必须要掌握的一个技术！
很多的数据类型用户的个人信息，社交网络，地理位置。这些数据类型的存储不需要一个固定的格式！
不需要多余的操作就可以横向扩展的 ！ Map&lt;String,Object&gt; 使用键值对来控制非关系型数据库(NOSQL)NOSQL：不仅仅是SQL
- 不仅仅是数据
- 没有固定的查询语言
- 键值对存储，列存储，文档存储，图形数据库（社交关系）
- 最终一致性，
- CAP定理和BASE （异地多活） 初级架构师！1. redis能做什么内存存储、持久化，内存中是断电即失、所以说持久化很重要（rdb、aof）效率高，可以用于高速缓存发布订阅系统地图信息分析计时器、计数器（浏览量！）2. redis特点特性多样的数据类型持久化集群事务3. Redis安装Linux中文官网：CRUG网站 (redis.cn)英文官网：Redis在官网中下载Redis的最新稳定版本即可，Redis是建议安装的，Linux可以下载.gz压缩文件，将压缩包解压到Linux服务器即可安装成功（我们可以解压到linux服务器中的/opt/目录中）4. 基本环境安装下载C++环境yum install gcc-c++
make
make install注意安装 redis执行make命令报错struct redisServer’没有名为‘sentinel_mode’的成员报错如图：1.解决安装 redis执行make命令报错struct redisServer’没有名为‘sentinel_mode’的成员查看gcc的版本是否在 5.3以上 命令：gcc -v\#升级到 5.3及以上版本命令：yum -y install centos-release-sclyum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutilsscl enable devtoolset-9 bash执行完毕之后去到src目录下执行make即可编译成功5. 启动Redis目前我使用的Linux centos 7 和Redis 6.X1.普通方式启动Redis使用 cd 命令进入Redis的安装目录，如：cd /opt/redis/src/查询目录下是否拥有 redis.server 如果有直接执行命令：./redis.server 若没有可以去目录 ·/usr/local/bin查找，然后执行./redis.server见到如图就是启动成功了我们会发现无法使用命令进行操作，这是因为redis的启动占用了当前线程，紧接着介绍第二种启动方式，也就是后台启动，是最常用的启动方式2. 后台线程方式启动Redis进入redis安装目录寻找配置后台启动配置文件redis.conf使用vi redis.conf命令编辑配置文件可以使用/ 命令查找对应的配置字母，修改如下配置值为yes使用命令wq 保存退出然后使用在安装目录使用命令./src/redis-server redis.conf （每个人的路径可能不一样，大概意思就是在启动方式1的基础上加上了配置文件的也叫配置文件启动方式）查询是否启动成功ps -ef | grep redis 找到redis的进程即是启动成功3. 关闭服务在可以直接使用Linux命令将线程kill掉，也可以在客户端工具中执行shutdown命令6. Redis客户端工具客户端工具的目录在Redis的安装目录中的/src/目录下，名称叫做redis.cli启动命令./redis.cli当输入命令更改为：127.0.0.1:6379&gt; 即为进入客户端工具成功退出可以使用ctrl+c直接强制退出可以命令ping 查看是否可以正常执行，返回PONG即表示成功7. Redis基础命令1. Redis的默认数据库redis默认有16个数据库，默认使用的是第0个数据库，可以使用select n 进行切换数据库select 3 # 切换数据库到第三个
DBSIZE # 查看数据库的大小2. 清空Redis数据库清空当前数据库：flushdb清空全部数据库的内容：flushall3. 查看所有的keykeys * # 查看所有的数据库8. Redis String(字符串)命令1. Setnx命令Redis Setnx（SET if Not eXists） 命令在指定的 key 不存在时，为 key 设置指定的值。语法：setnx &lt;k&gt; &lt;v&gt; # 如 key 为 name v 为 张三
setnx &lt;k&gt; &lt;v&gt; # 在第二次添加时，key为name时，不论值为什么都会添加失败2. getRange命令截取getRange 命令用于获取存储在指定 key 中字符串的子字符串。字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。语法：# 设置一个k v数据
SET mykey &quot;This is my test key&quot;
getrange mykey 0 3
# 输出 &quot;This&quot;
getrange mykey 0 -1
# 输出 &quot;This is my test key&quot;3. Mset命令Mset 命令用于同时设置一个或多个 key-value 对。# 设置多个k v键值对
mset k1 &quot;Hello&quot; k2 &quot;World&quot;4. Setex命令Setex 命令为指定的 key 设置值及其过期时间。如果 key 已经存在， Setex 命令将会替换旧的值。setex k1 60 &quot;v1&quot;
# 设置 60秒过期的k1 值为 v15.set命令SET 命令用于设置给定 key 的值。如果 key 已经存储其他值， SET 就覆写旧值，且无视类型。# 设置一个键值对 k1 v1
set k1 v16. get命令返回对应 key 的value值，如果 key 不存在时，返回 nil。 如果 key 不是字符串类型，那么返回一个错误GET db # 不存在返回 nil7. getBit命令Getbit 命令用于对 key 所储存的字符串值，获取指定偏移量上的位(bit)。# 对不存在的 key 或者不存在的 offset 进行 GETBIT， 返回 0
 
redis&gt; EXISTS bit
(integer) 0
 
redis&gt; GETBIT bit 10086
(integer) 0
 
 
# 对已存在的 offset 进行 GETBIT
 
redis&gt; SETBIT bit 10086 1
(integer) 0
 
redis&gt; GETBIT bit 10086
(integer) 18. setBit命令Setbit 命令用于对 key 所储存的字符串值，设置或清除指定偏移量上的位(bit)。setbit bit 10086 1
getbit bit 100869.Decr命令Decr 命令将 key 中储存的数字值减一。如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 DECR 操作。如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。set k1 10

decr k1 # 返回 9
# 对不存在的key值进行decr

decr k2 # 不存在赋值初始为0 再减一所以返回 -1

set k3 &quot;hello&quot;

decr k3 # 存在但不是数值的key会返回一个错误10. decrBy命令Decrby 命令将 key 所储存的值减去指定的减量值。如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 DECRBY 操作。如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。set k1 100

decrby k1 20 # K1 减去20 返回 80
# 其余的特点和decr一样11. Strlen命令Strlen 命令用于获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串值时，返回一个错误set k1 &quot;hello word&quot;

strlen k1 # 返回k1的字符串长度 11

# 若k不存在返回 012. Msetnx命令Msetnx 命令用于所有给定 key 都不存在时，同时设置一个或多个 key-value 对。当所有 key 都成功设置，返回 1 。 如果所有给定 key 都设置失败(至少有一个 key 已经存在)，那么返回 0# 对不存在的 key 进行 MSETNX
 
MSETNX rmdbs &quot;MySQL&quot; nosql &quot;MongoDB&quot; key-value-store &quot;redis&quot; # 添加多个k v键值对
 
MGET rmdbs nosql key-value-store # 查询多个k v 键值对
1) &quot;MySQL&quot;
2) &quot;MongoDB&quot;
3) &quot;redis&quot;
 
 
# MSET 的给定 key 当中有已存在的 key
 
Msetnx rmdbs &quot;Sqlite&quot; language &quot;python&quot;  # rmdbs 键已经存在，操作失败

# 因为 MSET 是原子性操作，language 没有被设置
 
GET rmdbs     # rmdbs 也没有被修改 输出 MySQL
13. ncrby命令Incrby 命令将 key 中储存的数字加上指定的增量值。如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCRBY 命令。如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。# key 存在且是数字值
 
SET rank 50 # 添加一个k

INCRBY rank 20 # rank存在添加20 返回70

# key 不存在时

INCRBY counter 30 # 不存在，初始化0返回30
 
# key 不是数字值时
SET book &quot;long long ago...&quot;
INCRBY book 200 # book 值不是数字，报错14. Incrbyfloat命令Incrbyfloat 命令为 key 中所储存的值加上指定的浮点数增量值。如果 key 不存在，那么 INCRBYFLOAT 会先将 key 的值设为 0 ，再执行加法操作。# 值和增量都不是指数符号
SET mykey 10.50 # 设置myke 值为10.50
 
incrbyfloat mykey 0.1 # mykey的值增加0.1
 
# 值和增量都是指数符号
 
SET mykey 314e-2 # 设置mykey值为 314e-2

GET mykey  # 用 SET 设置的值可以是指数符号&quot;314e-2&quot;
 
incrybyfloat mykey 0      # 但执行 INCRBYFLOAT 之后格式会被改成非指数符号
&quot;3.14&quot;
 
# 可以对整数类型执行
 
SET mykey 3

INCRBYFLOAT mykey 1.1 # 对整数类型数据增加1.1
# 后跟的 0 会被移除
SET mykey 3.0
GET mykey                                   # SET 设置的值小数部分可以是 0 显示 &quot;3.0&quot;
 
INCRBYFLOAT mykey 1.000000000000000000000    # 但 INCRBYFLOAT 会将无用的 0 忽略掉，有需要的话，将浮点变为整数
GET mykey 返回 &quot;4&quot;15.Setrange命令Setrange 命令用指定的字符串覆盖给定 key 所储存的字符串值，覆盖的位置从偏移量 offset 开始。set k1 &quot;hello&quot; #设置k1 的值为 hello 
setrange k1 1 &quot;333&quot; # 将k1 从索引2开始替换三个位数的字符，会替换掉ell 会返回h333o16. psetex命令Psetex 命令以毫秒为单位设置 key 的生存时间。psetex的使用方法和setex的使用方法一样，只不过设置的过期时间是以毫秒为单位17. Append 命令Append 命令用于为指定的 key 追加值。如果 key 已经存在并且是一个字符串， APPEND 命令将 value 追加到 key 原来的值的末尾。如果 key 不存在， APPEND 就简单地将给定 key 设为 value ，就像执行 SET key value 一样。append k1 &quot;test&quot; # 当k1不存在的时候会创建k1 值为 test等同于 set k1 &quot;test&quot;

set k2 &quot;demo&quot;
appent k2 &quot;add&quot; # 当k2存在的时候，会将字符添加到原来的值后面，会返回字符长度18. getSet命令Getset 命令用于设置指定 key 的值，并返回 key 旧的值。set name &quot;hello&quot; # 设置一个初始k
getset name &quot;word&quot; # 会返回显示hello，然后将name的值设置为word
get name #这个时候name的值是word19.  MgetMget 命令返回所有(一个或多个)给定 key 的值。 如果给定的 key 里面，有某个 key 不存在，那么这个 key 返回特殊值 nilset k1 &quot;v1&quot; # 添加
set k2 &quot;v2&quot; # 添加
mget k1 k2 k3 # 获取多个 不存在返回 nil

1) &quot;v1&quot;
2) &quot;v2&quot;
3) (nil)
20. Incr命令Incr 命令将 key 中储存的数字值增一。如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCR 操作。如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。set k1 20 
incr k1  # k1 加一
get k1 # 返回219.Redis 哈希(Hash)命令1.Hmset命令和Hset命令Hmset 命令用于同时将多个 field-value (字段-值)对设置到哈希表中。此命令会覆盖哈希表中已存在的字段。如果哈希表不存在，会创建一个空哈希表，并执行 HMSET 操作hset k1 f1 &quot;k1-vf1&quot; f2 &quot;k1-vf2&quot;  # hmset和hset使用方式一样，不过hmset在官方文档中说已经弃用
hget k1 f1 # hget2. Hmget命令Hmget 命令用于返回哈希表中，一个或多个给定字段的值。如果指定的字段不存在于哈希表，那么返回一个 nil 值。hset k1 f1 &quot;k1-vf1&quot; f2 &quot;k1-vf2&quot;
hmget k1 f1 f2 # hmget可以通过多个fild 获取到值3. Hgetall命令命令用于返回哈希表中，所有的字段和值。在返回值里，紧跟每个字段名(field name)之后是字段的值(value)，所以返回值的长度是哈希表大小的两倍。hset k1 fd1 fdv1 fd2 fdv2 fd3 fdv3 #添加数据

hgetall k1 # 查询数据

# 输出结果 前面是fdkey 后面跟着他的fdvalue
1) &quot;fd1&quot;
2) &quot;fdv1&quot;
3) &quot;fd2&quot;
4) &quot;fdv2&quot;
5) &quot;fd3&quot;
6) &quot;fdv3&quot;4. Hget命令命令用于返回哈希表中指定字段的值。# 字段存在
HSET site redis redis.com

HGET site redis # 输出结果&quot;redis.com&quot; 不存在返回nil5. Hexists命令用于查看哈希表的指定字段是否存在。如果哈希表含有给定字段，返回 1 。 如果哈希表不含有给定字段，或 key 不存在，返回 0 。hset k1 fd1 fdv1 fd2 fdv2 fd3 fdv3 #添加数据

hgetall k1 # 查询数据

hexists k1 fd4 # 不存在返回0
hexists k1 fd1 # 存在返回 16. Hincrby命令Hincrby 命令用于为哈希表中的字段值加上指定增量值。增量也可以为负数，相当于对指定字段进行减法操作。如果哈希表的 key 不存在，一个新的哈希表被创建并执行 HINCRBY 命令。如果指定的字段不存在，那么在执行命令前，字段的值被初始化为 0 。对一个储存字符串值的字段执行 HINCRBY 命令将造成一个错误。本操作的值被限制在 64 位(bit)有符号数字表示之内。hset k1 f1 20 # 添加一个key
hincrby k1 f1 1 # 给k1哈希表中的f1的值增加1
# 若不是数字类型，那么将报错7. Hlen命令Hlen 命令用于获取哈希表中字段的数量。hset k1 f1 v1 f2 v2
hlen k1 #返回 2 对应的k1哈希表中有两个字段分别是f1 f2,不存在返回08. Hdel命令Hdel 命令用于删除哈希表 key 中的一个或多个指定字段，不存在的字段将被忽略。hset k1 f1 v1 f2 v2 #添加初始数据
hdel k1 f2 # 删除k1哈希表中的f2字段 返回 1成功
hget k1 f1 # 返回v1
hget k1 f2 # 返回 nil
hdel k1 f3 #返回 0删除失败9.Hvals命令Hvals 命令返回哈希表所有字段的值。hset k1 f1 v1 f2 v2
hvals k1 # 返回 v1 v210. Hincrbyfloat命令Hincrbyfloat 命令用于为哈希表中的字段值加上指定浮点数增量值。如果指定的字段不存在，那么在执行命令前，字段的值被初始化为 0 。hset k1 f1 20.1
hincrbyfloat k1 f1 1.1 # 返回 21.211. Hkeys命令Hkeys 命令用于获取哈希表中的所有字段名。hset k1 f1 v1 f2 v2
hkeys k1 # 返回 f1 f212. Hsetnx 命令Hsetnx 命令用于为哈希表中不存在的的字段赋值 。如果哈希表不存在，一个新的哈希表被创建并进行 HSET 操作。如果字段已经存在于哈希表中，操作无效。如果 key 不存在，一个新哈希表被创建并执行 HSETNX 命令。hsetnx k1 f1 v1
hsetnx k1 f1 v2 # 操作无效，已经存在忽略
hget k1 f1 # 值是 v110. 其他命令其他命令可以进入官网进行自测官网：Redis命令中心（Redis commands） -- Redis中国用户组（CRUG）更多Redis资料：Redis 教程 | 菜鸟教程 (runoob.com)</description>
</item>
</rdf:RDF>