文章目录
- NoSQL之 Redis配置与优化
- 数据库类型
- 关系型数据库
- 非关系型数据库
- 关系型数据库SQL 和 非关系型数据库NoSQL 的区别?
- Redis
- Redis为什么那么快?
- Redis工具
- redis持久化
- redis性能优化
- redis的三大缓存问题
- 缓存雪崩解决方案
- 缓存穿透解决方案
- 缓存击穿解决方案
- Redis 安装部署
- 环境准备
- 具体流程
- Redis 命令工具
- redis-cli 命令行工具
- redis-benchmark 测试工具
- Redis 数据库常用命令
- string类型操作:(计数器)
- list类型操作:(消息队列)
- hash类型操作:(存储对象,购物车)
- set类型操作:(随机抽奖,求交集、差集、并集)
- zset类型操作:(排行榜,热搜)
- 修改密码
NoSQL之 Redis配置与优化
数据库类型
关系型数据库
实例–>数据库–>表(table)–>记录行(row)、数据字段(column)
非关系型数据库
实例–>数据库–>集合(collection)–>键值对(key-value)
非关系型数据库不需要手动建数据库和集合(表)。
关系型数据库SQL 和 非关系型数据库NoSQL 的区别?
SQL | NoSQL | |
---|---|---|
存储结构 | 二维表格结构 | 不是二维表格结构,不同的NoSQL采用不同的存储方式(键值对、文档、索引、图形结构、时间序列等) |
扩展方 | 纵向扩展(提升单机的硬件性能) | 横向扩展(增加服务器节点数量) |
事务支持 | 基于ACID原则,对事务控制更稳定、细粒度更高 | 基于BASE原则,对事务控制的稳定性和细粒度不如SQL |
典型代表 | MySQL、PostgreSQL、Oracle、SQL Server | Redis Memcached MongoDB ElasticSearch Prometheus Hbase |
Redis
- 定义:一款用C语言开发的,开源的,基于内存运行NoSQL
- 存储结构:键值对(Key/Value KV)
- 数据类型:五大基础数据类型 string(字符串) list(列表) hash(哈希/散列) set(集合/无序集合) zset/sorted set(有序集合)
- 特殊数据类型 HyperLogLogs(基数统计) Bitmaps (位图) geospatial (地理位置)
- 端口号:TCP/6379
Redis为什么那么快?
1)redis是基于内存运行,数据的读写都是在内存中完成的
2)数据结构简单,直接使用 键值对 的方式存储数据
3)数据读写采用单线程模式,避免了多线程切换带来的CPU性能损耗,同时也不用考虑各种锁的影响
4)采用IO多路复用模型,异步非阻塞IO可以使网络线程处理更多的网络连接请求,提高了网络并发能力
Redis工具
- 性能检测工具 redis-benchmark -h <redis服务器地址> -p <redis端口> -a <redis密码> -c <并发连接数> -n <总请求数> -d <请求的数据大小> -t <被测试的命令> -q
- 客户端命令行工具 redis-cli -h <redis服务器地址> -p <redis端口> -a <redis密码> #默认连接 127.0.0.1:6379
redis持久化
1)RDB持久化:定时的将redis在内存的数据进行快照并压缩保存到硬盘里
手动触发:手动执行 bgsave 命令
自动触发:满足配置文件中 save n m 的规则(在n秒内发生了m次数据更新就会自动触发);主从复制在做全量复制时;执行shutdown命令关闭数据库时
工作流程:redis主进程会fork子进程来进行RDB持久化快照保存内存数据到硬盘里,文件名为 dump.rdb
优缺点:RDB持久化保存的文件占用空间较小,网络传输快,恢复速度比AOF更快,性能影响比AOF更小
实时性不如AOF,兼容性较差,持久化期间在fork子进程时会阻塞redis主进程响应客户端命令
2)AOF持久化:实时的以追加的方式将redis写操作命令保存到aof文件里
工作流程:命令追加(将写操作命令追加到aof_buf缓冲区)
文件写入和同步(按照同步策略将缓冲区里的数据同步到硬盘,文件名:appendonly.aof;同步策略:everysec(每秒刷盘一次)、always(每条命令写入都刷盘)、no(让系统自行刷盘))
文件重写(减少aof文件占用空间和加快恢复速度,定时执行bgrewriteaof命令触发)
优缺点:实时性比RDB更好,支持秒级持久化,兼容性较好;
持久化保存的文件占用空间更大,恢复速度更慢,性能影响更大,AOF文件重写期间在fork子进程时也会阻塞redis主进程,且IO压力更大
RDB和AOF的区别可从 工作方式、实时性、占用空间、恢复速度、兼容性、IO性能影响 这几方面进行描述。
redis性能优化
1)设置内存上限(maxmemory),并设置内存数据淘汰策略(maxmemory-policy),一般采用lru或random
2)开启AOF持久化(实时性好),设置AOF刷盘策略为everysec;关闭自动AOF文件重写,采用定期在业务低峰期执行bgrewriteaof命令触发AOF文件重写,减少IO的压力
3)开启自动内存碎片清理(activedefrag yes)
4)缩短键值对存储长度,避免存储bigkey导致操作耗时(建议string类型数据控制在20KB以内,hash、list、set、zset控制元素数量在5000以内)
5)给key设置合理的过期时间,尽量避免大量key集中过期
6)开启lazy-free机制(lazyfree-lazy-* yes),将删除过期key的操作放到后台线程执行,减少大量的删除操作对redis主进程的阻塞
7)尽量使用物理机而非虚拟机部署redis服务,使用高速固态硬盘作为AOF日志的写入盘
8)使用分布式架构(主从复制、哨兵、集群)实现读写分离、分散bigkey来提升读写速度,并实现高可用
9)禁用内存大页(echo never > /sys/kernel/mm/transparent_hugepage/enabled),因为开启内存大页会到fork子进程的速度变慢,也会拖慢写操作的执行速度
redis的三大缓存问题
正常情况下,大部分的访问请求应该时先被redis缓存响应,在redis那里得不到响应的小部分访问请求才会去请求MySQL数据库获取数据,这样MySQL数据库的负载压力会非常小,能够正常稳定工作。
缓存雪崩/穿透/击穿问题的根本原因是在于redis缓存命中率下降,大量请求会直接发送给MySQL数据库,导致数据库负载压力过大而崩溃。
-
缓存雪崩:redis中大量不同的缓存key集中过期
-
缓存穿透:大量请求访问redis和MySQL数据库都不存在的数量
-
缓存击穿:redis中一个热点key过期,此时又有大量请求访问这个热点key
缓存雪崩解决方案
使用随机数设置key的过期时间,防止集中过期
设置二级缓存
使用互斥锁,在查数据库时加锁,缓冲大量请求
缓存穿透解决方案
使用布隆过滤器进行判断拦截一定不存在的无效请求
对空值数据也进行缓存
在业务层使用脚本等方式对用户的请求进行校验,排查非法请求
缓存击穿解决方案
对热点缓存不设置过期时间
预先对热点数据进行缓存预热
使用互斥锁,在查数据库时加锁,缓冲大量请求
Redis 安装部署
reids软件包下载地址:https://download.redis.io/releases/
环境准备
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i 's/enforcing/disabled/' /etc/selinux/config
#修改内核参数
vim /etc/sysctl.conf
vm.overcommit_memory = 1 #内核允许超量使用内存直到用完为止,防止OOM杀死进程
net.core.somaxconn = 2048 #指定处于监听状态的连接请求队列的最大长度
sysctl -p
具体流程
安装redis
yum install -y gcc gcc-c++ make
tar zxvf /opt/redis-7.0.15.tar.gz -C /opt/
cd /opt/redis-7.0.15
make
make PREFIX=/usr/local/redis install
#由于Redis源码包中直接提供了 Makefile 文件,所以在解压完软件包后,不用先执行 ./configure 进行配置,可直接执行 make 与 make install 命令进行安装。
#创建redis工作目录
mkdir /usr/local/redis/{conf,log,data}
cp /opt/redis-7.0.15/redis.conf /usr/local/redis/conf/
useradd -M -s /sbin/nologin redis
chown -R redis.redis /usr/local/redis/
#环境变量
vim /etc/profile
PATH=$PATH:/usr/local/redis/bin #增加一行
source /etc/profile
//修改配置文件
vim /usr/local/redis/conf/redis.conf
bind 127.0.0.1 20.0.0.51 #87行,添加 监听的主机地址
protected-mode no #111行,将本机访问保护模式设置no。如果开启了,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应
port 6379 #138行,Redis默认的监听6379端口
daemonize yes #309行,设置为守护进程,后台启动
pidfile /usr/local/redis/log/redis_6379.pid #341行,指定 PID 文件
logfile "/usr/local/redis/log/redis_6379.log" #354行,指定日志文件
dir /usr/local/redis/data #504行,指定持久化文件所在目录
requirepass abc123 #1037行,增加一行,设置redis密码
//定义systemd服务管理脚本
vim /usr/lib/systemd/system/redis-server.service
[Unit]
Description=Redis Server
After=network.target
[Service]
User=redis
Group=redis
Type=forking
TimeoutSec=0
PIDFile=/usr/local/redis/log/redis_6379.pid
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
#启动服务
systemctl start redis-server
systemctl enable redis-server
netstat -lntp | grep 6379
redis-cli -h 20.0.0.51 -p 6379 -a
Redis 命令工具
redis-server:Redis 服务器启动命令
redis-benchmark:性能测试工具,用于检测 Redis 在本机的运行效率
redis-check-aof:修复有问题的 AOF 持久化文件
redis-check-rdb:修复有问题的 RDB 持久化文件
redis-cli:Redis 客户端命令行工具
redis-sentinel:Redis 哨兵集群使用
redis-cli 命令行工具
语法:redis-cli -h host -p port [-a password]
-h :指定远程主机
-p :指定 Redis 服务的端口号
-a :指定密码,未设置数据库密码可以省略-a 选项
若不添加任何选项表示,则使用 127.0.0.1:6379 连接本机上的 Redis 数据库
redis-cli -h 192.168.80.10 -p 6379 -a 'abc123'
redis-benchmark 测试工具
redis-benchmark 是官方自带的 Redis 性能测试工具,可以有效的测试 Redis 服务的性能。
基本的测试语法:redis-benchmark [选项] [选项值]。
-h :指定服务器主机名。
-p :指定服务器端口。
-s :指定服务器 socket
-c :指定并发连接数。
-n :指定请求数。
-d :以字节的形式指定 SET/GET 值的数据大小。
-k :1=keep alive 0=reconnect 。
-r :SET/GET/INCR 使用随机 key, SADD 使用随机值。
-P :通过管道传输<numreq>请求。
-q :强制退出 redis。仅显示 query/sec 值。
--csv :以 CSV 格式输出。
-l :生成循环,永久执行测试。
-t :仅运行以逗号分隔的测试命令列表。
-I :Idle 模式。仅打开 N 个 idle 连接并等待。
#向 IP 地址为 192.168.80.10、端口为 6379 的 Redis 服务器发送 100 个并发连接与 100000 个请求测试性能
redis-benchmark -h 192.168.80.10 -p 6379 -c 100 -n 100000
#测试存取大小为 100 字节的数据包的性能
redis-benchmark -h 192.168.80.10 -p 6379 -q -d 100
#测试本机上 Redis 服务在进行 set 与 lpush 操作时的性能
redis-benchmark -t set,lpush -n 100000 -q
Redis 数据库常用命令
string类型操作:(计数器)
set 键 值
get 键
mset 键1 值1 键2 值2 ....
mget 键1 键2 ....
setex 键 秒 值 #创建键并设置过期时间
strlen 键 #统计键值的字符长度
incr 键 #数值递增+1
decr 键 #数值递减-1
incrby 键 N #数值递增+N
decrby 键 #数值递减-N
list类型操作:(消息队列)
lpush 键 值1 值2 值3 .... #从左边开始插入元素
rpush 键 值1 值2 值3 .... #从右边开始插入元素
lrange 键 起始下标 起始下标 #查询指定范围的元素,起始位置 0表示从左边开始的第一个元素,终止位置 -1表示到最后一个元素
lpop 键 N #显示并删除从左边开始的N个元素
rpop 键 N #显示并删除从右边开始的N个元素
llen 键 #统计元素的数量
lindex 键 元素下标 #查看指定位置的元素值,元素位置的下标从左往右,从0开始
lset 键 元素下标 值 #修改指定位置的元素值
lrem 键 N 元素值 #从左边开始删除N个指定元素
linsert 键 before|after 元素 值 #在指定元素前|后插入一个新元素
hash类型操作:(存储对象,购物车)
hset 键 字段 值
hmset 键 字段1 值1 字段2 值2 ....
hget 键 字段
hkeys 键 #查看所有字段名
hvals 键 #查看所有字段的值
hdel 键 字段 #删除字段
set类型操作:(随机抽奖,求交集、差集、并集)
sadd 键 值1 值2 .... #元素值不能重复
smembers 键 #查看元素,无序的
srem 键 值1 值2 .... #删除指定的元素
srandmember 键 N #随机显示N个元素
spop 键 N #随机显示N个元素并删除
scard 键 #统计元素的数量
smove 键1 键2 值 #将键1的元素移动到键2中
sinter 键1 键2 #求键1和键2的交集
sdiff 键1 键2 #求键1和键2的差集
sunion 键1 键2 #求键1和键2的并集
zset类型操作:(排行榜,热搜)
zadd 键 权重1 值1 权重2 值2 .... #score权重是可以重复的,元素值不能重复
zrange 键 起始下标 起始下标 withscores #根据元素下标查看元素,元素位置的下标从左往右,从0开始,-1为最后
zrangebyscore 键 起始权重 终止权重 #根据score从小到大的顺序查看元素
zrevrange 键 起始下标 起始下标 withscores #降序查看元素
zrevrangebyscore 键 起始权重 终止权重 #按照score从大到小的顺序查看元素
zcard 键 #统计元素的数量
zcount 键 起始权重 终止权重 #统计指定score范围的元素数量
zrem 键 值1 值2 .... #删除指定的元素
zincreby 键 权重 值 #再指定score位置添加元素
del 键 #删除键
type 键 #查询键的数据类型
keys 键 #查询键,支持通配符 * ?
exists 键 #判断键是否存在,1表示存在,0表示不存在
expire 键 秒 #为键设置过期时间
ttl 键 #查询键的过期时间,-2表示已过期,-1表示永不过期
rename 键 新键 #重命名键,会覆盖已存在的键
renamenx 键 新键 #重命名键,不会覆盖已存在的键
dbsize #统计当前库中键的总数
select 库ID #切换库,默认库ID范围为 0~15
move 键 库ID #移动键到指定的库
flushdb #清空当前库中的键(慎用)
flushall #清空所有库的键(慎用)
修改密码
config set requirepass '密码' #修改redis密码
config get requirepass #查询redis密码