redis高性能键值数据库技术简介

什么是redis

redis是远程字典服务(Remote Dictionary Server )的简写,是一个完全开源的高性能的Key-Value数据库,提供了丰富的数据结构如string、Hash、List、SetSortedset等等。数据是存在内存中的,同时Redis支持事务、持久化、LUA脚本、发布订阅、缓存淘汰、流技术等特性,提供了主从模式、Redis Sentinel和Redis cluster集群架构方案。

安装redis

yum方式安装

shell 复制代码
sudo yum install redis
sudo systemctl enable redis
sudo systemctl start redis

yum方式版本比较落后,无法安装最新版的redis,如果需要安装最新版本的redis需要使用源码安装的方式

源码方式安装

shell 复制代码
# 检查环境依赖
yum install gcc -y
# 下载Redis源码,一般下载到/opt目录下,/opt/software
wget http://download.redis.io/releases/redis-7.0.2.tar.gz
# 解压缩到当前目录(/opt/module)  
tar zxvf /opt/software/redis-7.0.2.tar.gz  
# 编译并安装 redis  (默认安装在/usr/local/bin目录下)
make && make install 
# 启动redis	
redis-server

安装目录(/usr/local/bin)中的文件结构

配置redis.conf文件

shell 复制代码
# 进入redis解压目录
cd redis-7.0.2
# 备份redis.conf文件
cp redis.conf redis.conf.bak
# 将redis改为后台执行,替换daemonize no为daemonize yes
sed -i 's/^daemonize no/daemonize yes/' "redis.conf"

# 将redis改为可在外网访问,替换bind 127.0.0.1 -::1为bind 0.0.0.0
sed -i 's/^bind 127.0.0.1 -::1/bind 0.0.0.0/' "redis.conf"

# 配置redis密码,这里使用root作为密码,替换requirepass foobared为requirepass root
sed -i 's/^# requirepass foobared/requirepass root/' "redis.conf"

# 按照配置文件要求启动redis服务
redis-server redis.cnof

redis数据类型

数据类型 解释 作用
String 字符串类型 二进制安全的数据类型,可以用来存储任何类型的数据
List 列表类型 Redis列表是简单的字符串列表,按照插入顺序排序
Hash 哈希表 存储键值对,使用存储对象
Set 集合类型 String类型的无序集合,集合中不能存在重复的数据。底层通过hash来实现
ZSet 有序集合 String类型的有序集合,集合中不能存在重复的数据。每个元素关联一个double类型的分数,底层通过hash来实现。
GEO 地理空间 地理位置,坐标、距离等
HyperLogLog 基数统计 在输入元素数量或体积非常大时,计算基数所需时间和空间总是固定的
Bitmap 位图 二进制的bit数组
Bitfield 位域 连续的比特位
Stream 用于消息队列(一般不是用)

String类型底层原理

String类型是redis最基本的数据类型,

SDS 简单动态字符串,SDS有的三个属性int len、int free、char buf[]。

len保存了字符串的长度

free表示buf数组中未使用的字节数量

buf数组则是保存字符串的每一个字符元素

Redis与C原生字符串相比:

1、C原生字符串不会记录长度,每次获取字符串长度时间复杂度都为O(n),Redis读取len中的数值即可,时间复杂度为O(1)。

2、C原生字符串拼接,如果分配空间不够会造成缓存区溢出的情况,SDS会现根据len中的数值判断空间是否足够,如果不够会进行相应的空间扩展,所以不会出现缓存区溢出的情况。

3、SDS提供空间预分配和惰性空间释放两种策略,在给字符串分配空间时,分配的空间比字符串实际所需空间大很多,这样能减少字符串增长带来的内存重新分配次数。当字符串被缩短时,SDS不会立即收回空间,而是通过free属性将空余的空间记录下来,等后面需要使用的时候再释放这些空间。

空间分配原则:当修改字符串后的长度len小于1MB,就会预分配和len一样长度的空间,即len=free;若是len大于1MB,free分配的空间大小就为1MB。
举个例子:
如果进行修改之后, SDS 的 len 将变成 13 字节, 那么程序也会分配 13 字节的未使用空间, SDS 的 buf 数组的实际长度将变成 13 + 13 + 1 = 27 字节(额外的一字节用于保存空字符)。
如果进行修改之后, SDS 的 len 将变成 30 MB , 那么程序会分配 1 MB 的未使用空间, SDS 的 buf 数组的实际长度将为 30 MB + 1 MB + 1 byte 。

List类型底层源码分析

redis3,2版本后,List类型通过quickList作为默认底层实现,quickList本质上是一个双端链表,可以认为是linkedList和ZipList的结合体。

LinkedList

LinkedList是一个普通的链表,LinkedList每一个节点的空间都是不连续的,所以可能造成过多的空间碎片。

ziplist

ziplist是为了节省内存而开发的一种压缩列表数据结构

zlbytes: 4字节,记录 ziplist 整个结构体的占用空间大小。用于内存重分配或计算zlend位置。

zltail: 4字节, 记录整个 ziplist 中最后一个 entry 的偏移量。用于快速定位到尾节点。

zllen: 4字节, 记录 entry 的数量,该值被固定为 2^16 - 1。 大于这个值就必须要遍历整个结构了。

entry: 真正存数据的结构。

zlend: 1字节, 为 ziplist 的结束标识。

entry节点结构

prelen:记录了前一个节点的长度。通过这个值,可以进行指针计算,从而跳转到上一个节点。如果前一节点的长度小于254字节,则prelen属性需要用1字节长的空间来保存;如果前一节点的长度大于等于254字节,则需要用5字节长的空间来保存。

encoding:记录了节点的content属性所保存数据的类型以及长度。编码的最高位用于标识数据类型(整数或字节数组),其余位用于表示内容的长度。

entry-data:保存节点的值

quicklist

quicklist存储了一个双向列表,每个列表的节点是一个ziplist

quicklist同样采用了linkedlist的双端列表特性,然后quicklist中的每个节点又是一个ziplist,所以quicklist就是综合平衡考虑了空间碎片和读写性能两个维度。使用quicklist需要注意以下2点:

1、如果ziplist中的entry个数过少,极端情况就是只有1个entry,此时就相当于退化成了一个普通的linkedlist。

2、如果ziplist中的entry过多,那么也会导致一次性需要申请的内存空间过大,而且因为ziplist本身的就是以时间换空间,所以会过多entry也会影响到列表对象的读写性能。

ziplist中的entry个数可以通过参数list-max-ziplist-size来控制

Redis持久化

redis为什么需要持久化?

Redis持久化的意义就是为了保证突然宕机,内存数据不会全部丢失。

RDB机制

RDB持久化是周期性的把redis当前内存中的全量数据写入到一个快照文件中

快照文件是一个二进制文件,包含了 Redis 在某个时间点内的所有数据。

在redis6.0之前,RDB的频率为15分钟1个变化、5分钟10个变化,1分钟1万个变化,

在redis6.2之后,RDB的频率为1小时1个变化,5分钟100个变化,1分钟1万个变化。

自动触发

再配置文件redis.conf中修改以下配置:

修改快照时间

save 5 2

修改文件保存路径

dir 文件路径

修改文件名称

dbfilename 文件名称.rdb

进入redis检查配置文件是否成功

config get save

config get dir

config get dbfilename

RDB会读取dump.rdb文件进行恢复,所以服务要与备份分机隔离。不可以把备份文件dump.rdb与生茶redis服务器放在同一台机器上,必须分开各自存储,以防止生产机物理损坏后备份文件也跟着挂了。

手动触发

手动执行有两个命令:save和bgsave

save:阻塞主进程,直到生成新的RDB文件;执行save命令期间,Redis不能处理其他命令。在生产中严禁使用该命令。

bgsave:异步生成RDB文件,fork子进程去生成新的RDB文件,主进程不阻塞。

相关推荐
程序员黄同学1 小时前
如何使用 Python 连接 MySQL 数据库?
数据库·python·mysql
新手小袁_J2 小时前
实现Python将csv数据导入到Neo4j
数据库·python·neo4j·《我是刑警》·python连接neo4j·python导入csv·csv数据集导入neo4j
シ風箏2 小时前
Neo4j【环境部署 02】图形数据库Neo4j在Linux系统ARM架构下的安装使用
linux·数据库·arm·neo4j
张声录12 小时前
【ETCD】【实操篇(四)】etcd常见问题快问快答FAQ
数据库·etcd
CherishTaoTao4 小时前
sqlite基础
数据库·oracle·sqlite
嶔某5 小时前
MySql:基本查询
数据库·mysql
开心工作室_kaic7 小时前
springboot461学生成绩分析和弱项辅助系统设计(论文+源码)_kaic
开发语言·数据库·vue.js·php·apache
毕设资源大全7 小时前
基于SpringBoot+html+vue实现的林业产品推荐系统【源码+文档+数据库文件+包部署成功+答疑解惑问到会为止】
java·数据库·vue.js·spring boot·后端·mysql·html
weisian1518 小时前
Redis篇--常见问题篇3--缓存击穿(数据查询上锁,异步操作,熔断降级,三种缓存问题综合优化策略)
数据库·redis·缓存
圆蛤镇程序猿8 小时前
【什么是事务?】
数据库·oracle