泛指菲关系型数据库。大规模数据存储,这些类型的数据存储不需要固定的模式,无需多余的操作就可以横向扩展
易扩展
去掉关系数据库的关系型特性,数据之间无关系,这样就非常容易扩展。
大数据量高性能
非常高的读写性能,关系型数据库使用Query Cache,每次表更新Cache就失效,Cache性能不高。NoSQL的Cache是记录级的,性能高
多样灵活的数据模型
传统RDBMS和NoSQL
RDBMS
NoSQL
海量
多样
实时
高并发
高可扩
高性能
KV键值
文档型数据库
MongoDB
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
CouchDB
列存储数据库
图关系数据库
CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。
而由于当前的网络硬件肯定会出现延迟丢包等问题,所以
分区容忍性是我们必须需要实现的。
所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。
C:强一致性 A:高可用性 P:分布式容忍性(分区容错性)
CA 传统Oracle数据库
AP 大多数网站架构的选择
CP Redis、Mongodb
注意:分布式架构的时候必须做出取舍。
一致性和可用性之间取一个平衡。多余大多数web应用,其实并不需要强一致性。
因此牺牲C换取P,这是目前分布式数据库产品的方向
一致性与可用性的决择
对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地
数据库事务一致性需求
很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低, 有些场合对写一致性要求并不高。允许实现最终一致性。
数据库的写实时性和读实时性需求
对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比方说发一条消息之 后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。
对复杂的SQL查询,特别是多表关联查询的需求
任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的报表查询,特别是SNS类型的网站,从需求以及产品设计角 度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。
Remote Dictionary Server远程字典服务器。C语言编写
是一个高性能的KV键值型分布式内存数据库,基于内存运行,并支持持久化的NoSQL数据库。(数据结构数据库)
使用Redis因为它读取数据快,直接从内存中读取,支持持久化,支持丰富的数据类型,支持事务,且拥有丰富的特性,可用于缓存,消息,设置key过期时间等等
单进程模型来处理客户端的请求。对读写等时间的响应是通过对epoll函数的包装来做到的。
默认16个数据库,类似数组下表从0开始,初始默认使用0号库
select命令切换数据库(0-15)
Dbsize查看当前数据库的key的数量
del 键名删除key
flushDB删除当前库数据(flushAll删除所有库数据)
统一密码管理,16个库一个密码
redis索引从0开始
默认端口6379
即value的数据类型
String
Hash哈希
List列表
Set集合
Zset有序集合(Sorted Set)
单值多value
实际上是一个字符串链表,left right都可以插入
如果键不存在,创建新的链表
已存在,新增内容
值全部移除,对应的键也就消失
单值多value
sadd/smembers/sismember
scard 获取集合里面的元素个数
srem keyname value 删除集合中元素
srandmember keyname N 随机出集合中N个数
spop keyname 随机出栈
smove key1 key2 key1中某个值:将key1中某个值赋给key2
sdiff/sinter/sunion 差交并
KV模式不变,但value是一个键值对
hset/hget/hmset/hmget/hgetall/hdel
hlen 返回hash中键值对个数
hexists keyname key
hkeys/hvals keyname:返回hash的键集合和值集合
hincrby/hincrbyfloat:自增
/opt/redis-xx-xx/redis.config
配置详解
持久化:将内存的数据写到磁盘上去,防止服务器宕机内存数据丢失
Redis DataBase
RDB文件:dumn.rdb
功能函数rdbSave生成RDB文件和rdbLoad从文件加载到内存中。
利用fork命令的copy on write机制,在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有数据,将数据写成RDB文件替换旧的RDB文件进行持久化。恢复时将快照文件直接读取到内存里。
缺点:数据库出问题,最后一次持久化后的数据可能丢失
整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能
如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方
式要比AOF方式更加的高效。
RDB文件是整个内存压缩过的snapshot快照,RDB的数据结构可以配置复合 的默认快照触发条件
save < seconds> < changes>
save 900 1 (15min修改过1次)
save 300 10 (5min修改过10次)
save 60 10000 (1min修改过10000次)
save " " 禁用
save/bgsave命令可立即备份(/usr/local/bin)
动态停止RDB保存规则的方法:redis-cli config set save " "
Append Only File
AOF文件:appendonly.aof
配置位置:redis.config中 appendonly no
将Redis执行的每次写命令记录到独立的日志文件中,Redis重启时再次执行AOF文件中的命令恢复数据
注意:写命令包括flushall
使用AOF时,如果同时存在dump.rdb和appendonly.aof时,可以共存,先加载appendonly.aof
修复aof文件:redis-check-aof --fix appendonly.aof
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,
当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,
只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof
重写原理:
AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),
遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,
而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
触发机制:Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
每修改同步:appendfsync always 同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
每秒同步:appendfsync everysec 异步操作,每秒记录 如果一秒内宕机,有数据丢失
不同步:appendfsync no 从不同步
相同数据集而言aof文件要远大于rdb文件,恢复速度慢于rdb
AOF运行效率慢于RDB,每秒同步策略好,不同步效率与RDB相同
RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
AOF持久化方式记录每次对服务器的写操作,当服务器重启时重写执行这些命令恢复数据。文件追加方式记录,文件过大时支持后台重写
只做缓存,可以不使用任何持久化方式
同时开启两种持久化方式
可以一次执行多个命令,本质是一组命令的集合。
一次事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不允许加塞
一次队列中,一次性、顺序性、排他性地执行一系列命令
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
一个事务从开始到执行会经历以下三个阶段:
序号 | 命令及描述 |
---|---|
1 | DISCARD 取消事务,放弃执行事务块内的所有命令。 |
2 | EXEC 执行所有事务块内的命令。 |
3 | MULTI 标记一个事务块的开始。 |
4 | UNWATCH 取消 WATCH 命令对所有 key 的监视。 |
5 | [WATCH key key …] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set a aaa
QUEUED
redis 127.0.0.1:6379> set b bbb
QUEUED
redis 127.0.0.1:6379> set c ccc
QUEUED
redis 127.0.0.1:6379> exec
1) OK
2) OK
3) OK
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set a a4
QUEUED
redis 127.0.0.1:6379> discard
OK
一次事务中出现错误(语法出现错误),事务内所有命令执行失败,exec报错所有语句得不到执行
语法本身没有错误,但适用对象错误,例如incr ,exec会执行正确的语句,并跳过有问题的语句
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
乐观锁机制,对key开启监控后,如果另一线程对key进行修改,当前线程开启事务multi,对key进行修改,exec执行事务失败。
监视一个或多个key,如果在事务执行之前这些key被其他命令所动,那么事务将被打断
redis 127.0.0.1:6379> set k1 v1
redis 127.0.0.1:6379> watch k1
redis 127.0.0.1:6379> multi
OK
此时另一个终端进行操作
redis 127.0.0.1:6379> set k1 v2
OK
执行完毕后,当前终端继续执行
redis 127.0.0.1:6379> set k1 k2
QUEUED
redis 127.0.0.1:6379> exec
(nil)
事务失败
unwatch取消对所有key的监控,一旦执行了exec之前加的监控锁都被取消
进程间的通信方式:消息队列,管道,套接字,共享内存,信号量
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
以下实例演示了发布订阅是如何工作的。在我们实例中我们创建了订阅频道名为 redisChat:
redis 127.0.0.1:6379> SUBSCRIBE c1 c2 c3
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "c1"
3) (integer) 1
1) "subscribe"
2) "c2"
3) (integer) 1
1) "subscribe"
2) "c3"
3) (integer) 1
现在,我们先重新开启个 redis 客户端,然后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。
redis 127.0.0.1:6379> PUBLISH c1 "message to c1"
(integer) 1
redis 127.0.0.1:6379> PUBLISH c2 "message to c2"
(integer) 1
# 订阅者的客户端会显示如下消息
1) "message"
2) "c1"
3) "message to c1"
1) "message"
2) "c2"
3) "message to c2"
下表列出了 redis 发布订阅常用命令:
序号 | 命令及描述 |
---|---|
1 | [PSUBSCRIBE pattern pattern …] 订阅一个或多个符合给定模式的频道。 |
2 | [PUBSUB subcommand argument [argument …]] 查看订阅与发布系统状态。 |
3 | PUBLISH channel message 将信息发送到指定的频道。 |
4 | [PUNSUBSCRIBE pattern [pattern …]] 退订所有给定模式的频道。 |
5 | [SUBSCRIBE channel channel …] 订阅给定的一个或多个频道的信息。 |
6 | [UNSUBSCRIBE channel [channel …]] 指退订给定的频道。 |
也就是我们所说的主从复制,主机数据更新后根据配置和策略,
自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主
作用
例:
配置6379 6380 6381端口的redis主机
通过info replication
指令查看三个redis主机信息,role均为master
如在6379进行设值
redis 127.0.0.1:6379> set k1 v1
OK
另外两个转为6379的从库,配置命令slaveof 主库IP 主库端口
redis 127.0.0.1:6379> slaveof 127.0.0.1 6379
OK
redis 127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
6379再次设值
redis 127.0.0.1:6379> set k2 v2
OK
此时两个从库数据已经从主库中全部复制过来,且执行info replication
指令发现从库role变为slave
读写分离只有主机能写,从机只能读
主机SHUTDOWN后,从机原地待命,角色不变;主机启动,恢复原状
从机SHUTDOWN,与master断开,每次断开之后都需要重新连接,除非配置进redis.config文件
上一个Slave可以是下一个slave的Master,Slave同样可以接收其他
slaves的连接和同步请求,那么该slave作为了链条中下一个的master,
可以有效减轻master的写压力
中途变更转向:会清除之前的数据,重新建立拷贝最新的
slaveof 新主库IP 新主库端口
通过命令SLAVEOF no one
可以配置为master角色
复制原理 |
---|
slave启动成功连接到master后会发送一个sync命令 |
Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令, 在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步 |
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。 |
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步 |
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行 |
能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
自定义sentinel.config文件,配置哨兵,填写内容
sentinel monitor 被监控数据库名字(自定义) 127.0.0.1 6379 1(票数)
启动哨兵
redis-sentinel /myredis/sentinel.conf
之前的master重启回来变为从库
复制延迟
由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。