一、关系型数据库与非关系型数据库
在Web应用发展的初期,那时关系型数据库受到了较为广泛的关注和应用,原因是因为那时候Web站点基本上访问和并发不高、交互也较少。而在后来,随着访问量的提升,使用关系型数据库的Web站点多多少少都开始在性能上出现了一些瓶颈,而瓶颈的源头一般是在磁盘的I/O上。而随着互联网技术的进一步发展,各种类型的应用层出不穷,这导致在当今云计算、大数据盛行的时代,对性能有了更多的需求,主要体现在以下四个方面:
- 低延迟的读写速度:应用快速地反应能极大地提升用户的满意度
- 支撑海量的数据和流量:对于搜索这样大型应用而言,需要利用PB级别的数据和能应对百万级的流量
- 大规模集群的管理:系统管理员希望分布式应用能更简单的部署和管理
- 庞大运营成本的考量:IT部门希望在硬件成本、软件成本和人力成本能够有大幅度地降低
为了克服这一问题,NoSQL应运而生,它同时具备了高性能、可扩展性强、高可用等优点,受到广泛开发人员的青睐。
1.1、关系型数据库
一个结构化的数据库,创建再关系型基础上
一般面向于记录
包括:Oracle、MySQL、SQL Server、Microsoft Access、DB2等
1.2、非关系型数据库
除了主流的关系型数据库外的数据库,都认为是非关系型
包括:Redis、MongBD、Hbase、CouhDB等
1.3、非关系型数据库产生背景
High performance——对数据库高并发读写需求
Huge Storage——对海量数据高效存储与访问需求
High Scalability && High Availability——对数据库高可扩展性与高可用性需求
二、Redis是什么
2.1、Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSIC编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性:
基于内存运行,性能高效
支持分布式,理论上可以无限扩展
key-value存储系统
开源的使用ANSIC语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API
2.2、相比于其他数据库类型,Redis具备的特点是:
- C/S通讯模型
- 单进程单线程模型
- 丰富的数据类型
- 操作具有原子性
- 持久化
- 高并发读写
- 支持lua脚本
2.3、哪些大厂在使用Redis?
- 微博
- 阿里巴巴
- 百度
- 美团
- 搜狐等
三、Redis的数据类型及主要特性
Redis提供的数据类型主要分为5种自有类型和一种自定义类型,这5种自有类型包括:String类型、哈希类型、列表类型、集合类型和有序集合类型。
3.1、String类型:
它是一个二进制安全的字符串,意味着它不仅能够存储字符串、还能存储图片、视频等多种类型, 最大长度支持512M。
对每种数据类型,Redis都提供了丰富的操作命令,如:
- GET/MGET
- SET/SETEX/MSET/MSETNX
- INCR/DECR
- GETSET
- DEL
3.2、哈希类型
该类型是由field和关联的value组成的map。其中,field和value都是字符串类型的。Redis是一个键值的集合。每个hash可以存储2的32次方-1个键值对
Hash的操作命令如下:
- HGET/HMGET/HGETALL
- HSET/HMSET/HSETNX
- HEXISTS/HLEN
- HKEYS/HDEL
- HVALS
3.3、列表类型
该类型是一个插入顺序排序、可以重复的字符串元素集合, 基于双链表实现。可以添加一个元素到列表的头部(左边)或者尾部,列表最多可存储2的32次方-1个元素
List的操作命令如下:
- LPUSH/LPUSHX/LPOP/RPUSH/RPUSHX/RPOP/LINSERT/LSET
- LINDEX/LRANGE
- LLEN/LTRIM
3.4、集合类型
Set类型是一种无顺序集合, 它和List类型最大的区别是:集合中的元素没有顺序, 且元素是唯一的。
Set类型的底层是通过哈希表实现的,其操作命令为:
- SADD/SPOP/SMOVE/SCARD
- SINTER/SDIFF/SDIFFSTORE/SUNION
Set类型主要应用于:在某些场景,如社交场景中,通过交集、并集和差集运算,通过Set类型可以非常方便地查找共同好友、共同关注和共同偏好等社交关系。
3.5、有序集合类型
ZSet是一种有序集合类型,每个元素都会关联一个double类型的分数权值,通过这个权值来为集合中的成员进行从小到大的排序。与Set类型一样,其底层也是通过哈希表实现的。
ZSet命令:
- ZADD/ZPOP/ZMOVE/ZCARD/ZCOUNT
- ZINTER/ZDIFF/ZDIFFSTORE/ZUNION
四、Redis配置文件
4.1、配置参数(/etc/redis/6379.conf)
bind | 监听的主机地址 |
---|---|
port | 端口 |
daemonize yes | 启用守护进程 |
pidfile | 指定PID文件 |
loglevel notice | 日志级别 |
logfile | 指定日志文件 |
4.2、key相关命令
keys | 获取符合规则的键值列表 |
---|---|
exists | 判断键值是否存在 |
del | 删除当前数据库的指定key |
type | 获取key对应的value值类型 |
rename(覆盖)/renamenx(不覆盖) | 重命名 |
dbsize | 查看当前数据库中key的数目 |
4.3、redis-benchmark测试工具
-h | 指定服务器的主机名 |
---|---|
-p | 指定服务器端口 |
-c | 指定并发连接数 |
-n | 指定请求数 |
-d | 以字节的形式指定SET/GET值的数据大小 |
-q | 强制退出Redis,仅显示query/sec值 |
5.1、操作步骤
解压软件包—→make && make install—→设置Redis相关配置文件—→查看运行状态
5.2、编译安装Redis
[root@server1 ~]# tar zxf redis-5.0.7.tar.gz
[root@server1 ~]# cd redis-5.0.7/
[root@server1 redis-5.0.7]# make -j2
[root@server1 redis-5.0.7]# make PREFIX=/usr/local/redis install
[root@server1 redis-5.0.7]# ln -s /usr/local/redis/bin/* /usr/local/bin #将redis的所有命令拷贝到/usr/local/bin目录下,可以更便捷的使用
5.3、设置Redis相关配置文件
[root@server1 ~]# cd redis-5.0.7/
[root@server1 redis-5.0.7]# cd utils/
[root@server1 utils]# ./install_server.sh #执行安装服务脚本
Welcome to the redis service installer
This script will help you easily set up a running redis server
Please select the redis port for this instance: [6379] #确定端口号
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] #redis配置文件
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] #日志文件
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] #数据存放目录
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server]
Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /var/lib/redis/6379
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
5.4、登录redis
[root@server1 src]# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379>
5.5、数据类型
5.5.1、string(字符串)是redis最基本的类型
举例
127.0.0.1:6379> set hobby dancing
OK
127.0.0.1:6379> get hobby
"dancing"
127.0.0.1:6379> set job singger
OK
127.0.0.1:6379> get job
"singger"
5.5.2、Hash(哈希字典),适合存储对象
举例
1 127.0.0.1:6379> hmset stu name Ammy hobby singger sex 女
2 OK
3 127.0.0.1:6379> hget stu name
4 "Ammy"
5 127.0.0.1:6379> hget stu hobby
6 "singger"
7 127.0.0.1:6379> hget stu sex
8 "\xe7\x94\xb7"
9 ###--raw 解决中文乱码问题
10 [root@server1 src]# redis-cli -h 127.0.0.1 -p 6379 --raw
11 127.0.0.1:6379> hget stu sex
12 女
5.5.3、List(列表)
举例
127.0.0.1:6379> lpush hobby read
1
127.0.0.1:6379> lpush hobby sing
2
127.0.0.1:6379> lpush hobby play game
3
127.0.0.1:6379> lrange hobby 0 5
play game
sing
read
127.0.0.1:6379> lrange hobby 0 0
read
127.0.0.1:6379> lrange hobby 1 1
sing
127.0.0.1:6379> lrange hobby 2 2
play game
###最先放入的数据拍照最后,就相当于在瓶子里放东西,最后被放进去的,取出来时是第一个被取出来的
5.5.4、Set(集合)是string类型的无序的集合
集合是通过哈希表实现的,所有添加,删除,查找的复杂度都是0(1)
作用场景:
- 共同好友
- 利用唯一性,统计访问网站的所有独立ip
- 好友推荐时,根据tag求交集,大于某个阈值就可以推荐
举例
127.0.0.1:6379> sadd color black write pink blue
4
127.0.0.1:6379> smembers color
black
write
pink
blue
127.0.0.1:6379> sadd color pink
0
##去重
5.5.5、zset(有序集合)
举例
127.0.0.1:6379> zadd color1 0 black
1
127.0.0.1:6379> zadd color1 0 pink
1
127.0.0.1:6379> zadd color1 1 write
1
127.0.0.1:6379> zadd color1 1 blue
1
127.0.0.1:6379> zrangebyscore color1 0 10
black
pink
write
blue
127.0.0.1:6379> zadd color1 0.5 orange
1
127.0.0.1:6379> zrangebyscore color1 0 10
black
pink
orange
write
blue
##插入的0.5在0和1之间
六、Redis持久化
6.1、持久化概述
Redis是运行在内存中,内存中的数据断电丢失
为了能够重用Redis数据,或者防止系统故障,需要将Redis中的数据写入到磁盘空间中,即持久化
6.2、持久化分类
- RDB方式:创建快照的方式获取某一时刻Redis中所有数据的副本
- AOF方式:将执行的写命令写到文件的末尾,以日志的方式来记录数据的变化
6.3、RDB持久化
Redis的默认持久化方式
默认文件名dump.rdb
触发条件
- 在指定的时间间隔内,执行指定次数的写操作(配置文件控制)
- 执行save或者是bgsave(异步)命令
- 执行flushall命令,清空数据库所有数据
- 执行shutdown命令,保证服务器正常关闭且不丢失任何数据
6.3.4、优缺点
- 适合大规模的数据恢复
- 如果业务对数据完整性和一致性要求不高,RDB是很好的选择
- 数据的完整性和一致性不高
- 备份时占用内存
6.3.5、通过RDB文件恢复数据
将dump.rdb文件拷贝到redis的安装目录的bin目录下,重启redis服务即可
6.3.6、配置文件选项
[root@server1 src]# vim /etc/redis/6379.conf
save 900 1 #900秒之内至少一次写操作
save 300 10 #300秒之内至少发生10次写操作
save 60 10000 #60秒之内发生至少10000次写操作,只要满足其一都会触发快照操作,注释所有的save项表示关闭RDB
dbfilename dump.rdb #RDB文件名称
dir /var/lib/redis/6379 #RDB文件路径
rdbcompression yes #是否进行压缩
6.4、AOF持久化
Redis默认不开启
弥补RDB的不足(数据的不一致性)
采用日志的形式来记录每个写操作,并追加到文件中
Redis重启会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
根据AOF文件恢复数据
将appendonly.aof文件拷贝到Redis的安装目录的bin目录下,重启Redis服务即可
配置文件选项
[root@server1 src]# vim /etc/redis/6379.conf
appendonly yes #开启AOF持久化
appendfilename "appendonly.aof" #AOF文件名称
# appendfsync always
appendfsync everysec #always:同步持久化,每次发生数据变化会立刻写入磁盘;everysec:默认推荐,每秒异步记录一次(默认值);no:不同步,交给操作系统决定如何同步
# appendfsync no
aof-load-truncated yes #忽略最后一条可能存在问题的指令
[root@server1]# cd /var/lib/redis/6379/
[root@server1 6379]# ll
总用量 8
-rw-r--r--. 1 root root 0 11月 10 12:06 appendonly.aof
-rw-r--r--. 1 root root 175 11月 10 12:26 dump.rdb
-rw-r--r--. 1 root root 781 11月 10 12:26 nodes-6379.conf
七、测试
7.1、为6379的Redis服务器发生100并发连接数10000个请求数
[root@server1 src]# redis-benchmark -h 20.0.0.10 -p 6379 -c 100 -n 10000
====== PING_INLINE ======
10000 requests completed in 0.05 seconds
100 parallel clients
3 bytes payload
keep alive: 1
99.05% <= 1 milliseconds
99.58% <= 2 milliseconds
100.00% <= 2 milliseconds
200000.00 requests per second
###省略部分内容###
====== MSET (10 keys) ======
10000 requests completed in 0.05 seconds
100 parallel clients
3 bytes payload
keep alive: 1
100.00% <= 0 milliseconds
217391.30 requests per second
7.2、存取大小为100字节的数据包的性能
[root@master1 src]# redis-benchmark -h 20.0.0.10 -p 6379 -q -d 100
PING_INLINE: 221238.94 requests per second
PING_BULK: 216450.20 requests per second
SET: 229357.80 requests per second
GET: 226757.36 requests per second
INCR: 224215.23 requests per second
LPUSH: 175746.92 requests per second
RPUSH: 168067.22 requests per second
LPOP: 203665.98 requests per second
RPOP: 219298.25 requests per second
SADD: 222717.16 requests per second
HSET: 227790.42 requests per second
SPOP: 224719.11 requests per second
LPUSH (needed to benchmark LRANGE): 172413.80 requests per second
LRANGE_100 (first 100 elements): 84745.77 requests per second
LRANGE_300 (first 300 elements): 33233.63 requests per second
LRANGE_500 (first 450 elements): 22794.62 requests per second
LRANGE_600 (first 600 elements): 16926.20 requests per second
MSET (10 keys): 185873.61 requests per second
7.3、测试本机上Redis服务在进行set与lpush操作时的性能
[root@master1 src]# redis-benchmark -h 20.0.0.10 -p 6379 -t set,lpush -n 100000 -q
SET: 233644.86 requests per second
LPUSH: 204081.62 requests per second
八、Redis性能管理
8.1、内存碎片率
操作系统分配的内存值used_memory_rss除以Redis使用的内存值used_memory计算得出
内存碎片是由操作系统低效的分配/回收物理内存导致的
不连续的物理内存分配
跟踪内存碎片率对理解Redis实例的资源性能是非常重要的
- 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低
- 内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率
- 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换
8.2、内存使用率
8.2.1、redis实例的内存使用率超过可用最大内存,操作系统将开始进行内存与swap空间交换
避免内存交换
- 针对缓存数据大小选择
- 尽可能的使用Hash数据结构
- 设置key的过期时间
8.3、回收key
保证合理分配redis有限的内存资源
当达到设置的最大阀值时,需选择一种key的回收策略
- 默认情况下回收策略是禁止删除
- redis.conf配置文件中修改maxmemory-policy属性值
volatile-lru | 使用LRU算法从已设置过期时间的数据集合中淘汰数据 |
---|---|
|volatile-ttl | 从已设置过期时间的数据集合中挑选即将过期的数据淘汰 |
volatile-random | 从已设置过期时间的数据集合中随机挑选数据淘汰 |
allkeys-lru | 使用LRU算法从所有数据集合中淘汰数据 |
allkeys-random | 从数据集合中任意选择数据淘汰 |
no-enviction | 禁止淘汰数据 |
大内存,操作系统将开始进行内存与swap空间交换
避免内存交换
- 针对缓存数据大小选择
- 尽可能的使用Hash数据结构
- 设置key的过期时间
8.3、回收key
保证合理分配redis有限的内存资源
当达到设置的最大阀值时,需选择一种key的回收策略
- 默认情况下回收策略是禁止删除
- redis.conf配置文件中修改maxmemory-policy属性值
volatile-lru | 使用LRU算法从已设置过期时间的数据集合中淘汰数据 |
---|---|
|volatile-ttl | 从已设置过期时间的数据集合中挑选即将过期的数据淘汰 |
volatile-random | 从已设置过期时间的数据集合中随机挑选数据淘汰 |
allkeys-lru | 使用LRU算法从所有数据集合中淘汰数据 |
allkeys-random | 从数据集合中任意选择数据淘汰 |
no-enviction | 禁止淘汰数据 |