Redis
windows下载地址
https://github.com/microsoftarchive/redis/releases/download/win-3.0.504/Redis-x64-3.0.504.msi
安装后redis服务默认会启动
SDS
simple dynamic string
SDS是redis底层使用的字符串结构
1 | struct sdshdr { |
保留了\0字符,目的是为了复用c语言中的字符串方法
buf.length = len + 1 + free
其中free为每次分配空间进行的预分配内存,避免每次扩展字符串时都需要重新申请空间。以1M为限,1M下会分配即将用到的内存的两倍,1M以上只多分配1M,避免指数爆炸。当然如果free本身就能够支持本次操作,则不会进行内存重分配。
free空间为惰性释放,当对字符串进行缩短操作时,会将回收的内存放在free中而不是会立即释放,便于后续使用,同时SDS提供了对应的释放api避免造成内存浪费。
此外,SDS为二进制安全的,由于不会通过终止符判断是否到信息结尾,故可以存储二进制数据即使其中包含\0,保证数据在存储与读取时的一致性
链表
1 | typedef struct listNode { |
双向无环链表,带头指针和尾指针,且带链表长度,同时结点的值为void指针类型,故具有多态性。
字典
RedisTemplate
spring默认提供的redisTemplate并不好用,这里使用自定义的RedisTemplate<String, Object>
redis连接
1 | spring: |
redis配置
1 | // 这里的Configuration是为了使下面的@Bean生效 |
调用
1 |
|
EnableRedisRepositories
使用
实体类配置
指定实体类中的id,并将实体类加@RedisHash(“student”)的注解,将会以student:id为key的方式存入redis
1 |
|
Dao与Service
Dao
1 |
|
泛型中第一位为存储类型,第二位为id的类型
Service
1 |
|
调用
1 |
|
保护模式
redis默认开启保护模式。要是配置里没有指定bind和密码,开启该参数后,redis只能本地访问,拒绝外部访问。
redis.conf安全设置: # 打开保护模式 protected-mode yes
Redis 的保护模式是一种安全特性,它限制了 Redis 服务器的访问权限。当保护模式被启用时,如果没有设置 bind 参数和密码,Redis 服务器将只接受来自本地主机的连接。这意味着,外部客户端将无法连接到 Redis 服务器,除非它们在同一个局域网内或具有相应的权限。
具体来说:
- bind 参数:
bind参数用于指定 Redis 服务器应该绑定的 IP 地址。如果未设置此参数,Redis 将绑定到所有可用的网络接口。但当保护模式被启用时,如果未设置bind参数,Redis 将只接受来自 localhost(127.0.0.1)的连接。 - 密码:为了从外部访问 Redis,你可以设置密码。当保护模式被启用时,如果你没有设置密码,外部客户端将无法连接到 Redis 服务器,除非它们具有适当的权限或位于相同的局域网内。
因此,当 Redis 的保护模式被启用且没有设置 bind 和密码时,Redis 服务器的访问将被限制在本地机器上。这有助于增强服务器的安全性,防止未经授权的访问。
禁用或者重命名危险命令
Redis中线上使用keys *命令是非常危险的,应该禁用或者限制使用这些危险的命令,可降低Redis写入文件漏洞的入侵风险。
KEYS *命令在 Redis 中用于列出所有的键。当 Redis 服务器正在处理这个命令时,它会遍历整个键空间,这可能会导致长时间的阻塞,尤其是在有大量数据的情况下。- 更糟糕的是,如果有外部攻击者恶意地使用
KEYS *命令,它可能会导致 Redis 服务器资源耗尽,从而拒绝服务。
修改 redis.conf 文件,添加
1 | rename-command FLUSHALL "" |
然后重启redis。
重命名为”” 代表禁用命令,如想保留命令,可以重命名为不可猜测的字符串,如:rename-command FLUSHALL joYAPNXRPmcarcR4ZDgC
启用远程连接
修改redis.conf文件,linux在/etc/redis下
- 修改protcted-mode为false
- 将bind一行注释
- requirepass 后面设置密码
启用密码后的cli连接
redis-cli之后,需要使用 auth password 进行认证,否则无权限操作
远程:redis-cli -h host -p port -a password
Hash过期
hash类型数据无法为单独的每条数据设置过期时间,只能为整个hash结构设置过期时间,如果有需求,建议在单个字段中存储过期时间手动判断
日志记录
linux下redisc.onf文件在etc的redis下面,编辑该文件,找到logfile一行,改行为日志文件所在地址
redis被攻击记录
redis关掉了保护模式与bind,密码设为了123456
现象,redis在备份rdb文件时出错,显示日志如下:
1 | * 1 changes in 900 seconds. Saving... |
其中奇怪的地方,一个是出现了一个主机,另一个是备份文件夹变成了只读
首先没有配置过主从复制,其次查看配置文件中,备份文件夹的地址为 /var/lib/redis,可见配置被动态修改了
建议配置方式
- 单独为redis设置一个普通账号启动 redis
- 设置本地 localhost 不允许外部访问
- 保护模式开启 protected-mode 开启 (默认开启)
- 把端口最好更改
- requirepass 设置redis密码
好在使用apt安装的redis,且使用systemctl启动redis,这样redis的所属用户为redis,没有系统文件夹比如进程等的操作权限
systemctl启动redis的配置
使用systemctl start redis命令启动Redis服务时,默认情况下会以redis用户的身份运行。这是通过systemd的单元文件来配置的,该文件定义了服务的运行方式。
要查看Redis服务的用户配置,可以执行以下步骤:
- 打开Redis服务的单元文件。在大多数Linux发行版上,Redis服务的单元文件位于
/etc/systemd/system/redis.service或/lib/systemd/system/redis.service。 - 使用文本编辑器打开该文件。
- 在文件中查找
User行。该行指定了运行Redis服务的用户。它应该类似于以下内容:
1 | User=redis |
- 如果你想更改运行Redis服务的用户,只需将
User行中的值修改为你想要的用户名,并保存文件。 - 重新加载
systemd配置并重新启动Redis服务,以使更改生效。可以使用以下命令:
1 | sudo systemctl daemon-reload |
请注意,更改运行Redis服务的用户需要具有适当的系统权限,并且确保新的用户具有访问Redis所需的文件和目录的权限。此外,确保在更改用户配置之前备份原始的单元文件,以便在需要时可以还原。
REDLOC
分布式的服务如果要做锁,考虑到使用redis实现,redloc是redis作者推荐的工具,但现在该工具已经不建议使用
Lua脚本
lua脚本实在redis层面执行的,由于redis是单线程,故可以保证原子性
三大漏洞
缓存穿透
查询一个不存在的数据时,mysql中也没有该数据,所以缓存一直不存在,导致会一直查询数据库
- 将空数据也进行缓存
- 或者使用布隆过滤器
缓存击穿
当key过期的时候恰好有大量目标为该key的请求,导致数据库承担大量压力
- 互斥锁:当一个请求发现缓存过期,就重新查询,此时给该缓存加锁,不允许其他读写行为,等缓存重新生成再释放
- 逻辑过期:不设置过期时间,但是存一个时间戳,这样可以先返回过期后的数据,然后开个线程更新缓存
缓存雪崩
大量key同时失效导致数据库压力变大
- 给不同的key加随机ttl
- 使用集群
- 给缓存添加限流降级
- 给业务添加多级缓存
数据库与redis同步
读时添加共享锁,写时添加排他锁
使用redisson的实现
排他锁底层使用的是setnx
延时双删:在有更新数据库数据动作时,先把缓存中的数据删除,然后更新数据库,过一段时间再删除缓存中的数据(避免在从数据库读取的时候有其他线程读取了旧数据并更新了缓存)
两种备份方式
RDB
对整个内存做快照,但备份时会有新数据进来所以不完整,文件体积小,恢复时速度较快
AOF
记录每次命令,相对完整,但文件大,恢复慢,但相较于RDB数据较安全
两种过期策略
- 惰性:读时检查
- 定期:定期检查
- slow模式 频率地,用时长
- fast模式 频率高,用时短
数据淘汰策略
默认是内存不足直接报错
LRU:最近最少使用
LFU:最少频率使用
常用为allkeys-lru
分布式锁
redisson,底层使用setnx和lua脚本实现
在redisson中,为保证使用过程中锁不过期,使用看门狗策略,每十秒续期一次
由于redisson底层同时会存储线程id(hash结构),故同一线程中的锁是可重入的
主从数据一致性需要使用红锁:给每个实例加锁,但影响性能
主从同步
实现读写分离
全量同步
- 从节点请求主节点数据
- 主节点判断是否为第一次请求,若是则从节点同步版本信息
- 主节点执行bgsave,生成rdb文件,发送给从节点
- rdb生成期间,记录aof类日志
- 将rdb发送后,将aof也发过去
增量同步
从节点判断不是第一次请求后,将从节点版本到主节点版本之间的数据发给从节点
高可用
哨兵模式
一般一主一从一哨兵
集群脑裂
主节点没有宕机,但是哨兵找不到主节点了,导致哨兵会推举一个新的主节点,而客户端还会继续往主节点中写数据,在网络恢复后,哨兵会将主节点作为从节点,从新的主节点中同步数据,导致期间数据丢失。
可以设置从节点数量与同步延时时间
分片集群
将大量数据根据id分区存储,集群中多个master,每个master存储不同分区的数据,客户端可访问任意节点,会被转发到正确的节点
