NoSQL概述
什么是NoSQL
NoSQL(Not Only SQL):意为不仅仅是SQL,泛指非关系型数据库
关系型数据库:行+列,同一个表下数据结构是一样的;将数据存储在磁盘上非关系型数据库:数据存储没有固定的格式;将数据存储在内存中
- 不依赖业务逻辑方式存储,而以简单的key-value键值对方式存储。因此大大增加了数据库的扩展能力
- 不遵循SQL标准(即增删改查)
- 不支持ACID(即不支持事务的四大特性)
NoSQL的使用场景
适用于:
- 对数据高并发的读写数据量巨大的读写
- 数据要求高可扩展性
不适用于: - 需要事务支持(不支持事务)基于sql的结构化查询存储
- 处理复杂的关系(因为是用key-value方式存储的,无法形成复杂的关系关联)需要条件查询(原因同上)
NoSQL的特点
- 方便扩展:数据之间没有关系,扩展时不需要考虑其他数据
- 大数据量高性能:Redis一秒可以写8万次,读11万次,因为其数据结构简单,且NoSQL的缓存是记录级的,粒度较细,可大大提高读写速度
- 数据类型灵活多样:NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式非关系型数据库,没有固定的查询语言
NoSQL数据库的四大分类
KV键值对型数据库:
Memcache数据库(支持简单的key-value模式,不支持持久化);
Redis数据库(相当于Memcache的升级版,支持多种数据结构存储,支持持久化);文档型数据库
MongoDB数据库(内部是一个环型链表结构,支持先进先出,当存储耗尽的时候,会释放最先进队列的数据,支持存储图片)
列存储数据库
按照列来存储数据(MySQL是按照行来存储数据),主要应用于分析数据,如:查询一张表中的平均年龄
HBase数据库图关系数据库
存储的不是图片,而是数据之间的关系网络,主要应用于广告推荐和社交网络Neo4j数据库
Redis
什么是Redis
Redis是一个开源的key-value型数据库,支持存储多种value类型;其数据缓存在内存中,
并周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并在此基础上实现了主从同步
Redis的作用
配合关系型数据库做高速缓存:
针对高频次,热点访问的数据,将其存入redis中,降低数据库IO针对分布式架构,做session共享
由于其可持久化,可以利用其多样的数据结构存储特定的数据:
Redis环境搭建
以linux系统的Redis安装配置为例安装:
-
下载redis安装包 redis-5.0.8.tar.gz ,将其放在 /opt 目录下
-
解压安装包: tar-zxvf redis-5.0.8.tar.gz
-
在执行之前,要先下载 gcc 和 gcc-c++ 环境支持(因为redis是使用c语言支持的)
-
进入到redis的解压目录下,执行编译并安装
-
安装好的redis默认在 usr/local/bin 目录下
yum install gcc
yum install gcc-c++
cd redis-5.0.8.tar.gz make
make install
配置
安装好的redis默认是前台启动的,需要修改其配置文件 redis.conf ,将其更改为后台启动
0. 备份 redis.conf :拷贝一份 redis.conf 到其他目录,这里我们在 /opt 文件夹下新建一个myredis 文件夹
mkdir /opt/myredis
cp redis.conf /opt/myredis/redis.conf
2. 复制完成后,进入 myredis 文件夹,打开 redis.conf 配置文件,将其中的 daemonize no 修改为 yes (默认后台启动)
vim redis.conf
测试
0. 通过指定配置文件启动redis服务器
redis-server /myredis/redis.conf
2. 查看redis服务器进程是否开启,如果正常开启,将显示主机ip地址和端口号
ps -ef|grep redis
3. 开启redis客户端,并连接指定服务器
redis-cli -h 服务器ip地址(127.0.0.1)-p 端口号(6379)
4. 测试是否连接成功,输入指令 ping ,输出 PONG 则连接成功
4. 关闭服务端: shutdown
4. 关闭客户端: exit
Redis基础知识
redis的数据库设计
redis有16个数据库,默认使用第1个数据库(即0号数据库)
可以使用 select index 指令选择使用第几个数据库,如: select 1 ,使用0号数据库使用 DBSIZE 指令可以查看数据库大小,这里的大小是由存储的键值对数量决定的redis的底层技术
redis使用单线程+多路IO复用技术redis执行速率快的原因:
单线程:redis将所有的数据存储在内存上,读写操作发生在内存上,使用单线程没有频繁的上下文切换(多线程会产生频繁的上下文切换),所有读写都是在一个CPU上的,所以效率高
多路IO复用技术:使用一个线程来检查多个文件描述符(Socket)的就绪状态,也就是给网络中的所有请求,提供一个监视的效果,如果一个请求准备就绪,直接让redis对请求进行处理,避免了阻塞(在阻塞IO中,如果CPU调用队首的一个请求,但该请求还没有到达就绪状态,CPU只能等待该请求进入就绪状态)过程带来的效率损耗
redis的基本指令
set key val :设置键值对get key :获取指定键的值
keys* :查询当前数据库的所有键exists <key :判断某个键是否存在type <key :查看键的类型
del <key :删除某个键
expire <key <seconds :为键值对设置过期时间,单位秒
ttl <key :查看还有多少秒过期,-1表示永不过期;-2表示已过期Flushdb :清空当前数据库
Flushall :清空所有数据库
# Redis五大数据类型 数据类型可以看下面:juejin.cn/post/684490…
## String
String是Redis最基本的类型,单键单值,是二进制安全的,意味着String类型可以包含任何数据,如:jpg图片;序列化json对象,一个String类型的Redis其value最大可以达到512M方法:
append key1 "String" :在指定的key对应的value后追加字符串,如果key不存在,相当于 set key val
strlen key1 :获取指定的key对应value字符串的长度
incr/decr key1 :对指定的key的value进行自增/自减操作,其value只能是数字(相当于++i/--i )
incrby/decrby key1 index :将指定的value自增/自减指定的步长(index)
getrange key1 in1 in2 :截取value字符串,截取 [in1,in2] 区间的字符串并返回setrange key1 begin target :用target替换指定位置开始的字符串
mset k1 v1 k2 v2... :同时设置多个键值对mget k1 k2 k3... :同时获取多个键对应的值**使用场景**:
value除了可以存放字符串,还可以存放数字样式的字符串("1"),可以用于计数器,数量统计,对象缓存存储
list
list是单键多值的,也就是说一个key对应多个一个list,list中存储任意个value,其底层是双向链表,允许两端进行操作,
其中list中存储的也是字符串。
方法:
lpush/rpush key v1 v2 v3 :从左边/右边插入一个或多个值
lpop/rpop key :从左边/右边取出一个值。当值都取空后,键也跟着销毁lrange key in1 in2 :获取指定区间的元素
llen key :获取指定key对应list的长度
linsert key before olval newval :在旧值 olval 后面插入新值 newval lrem key n value :移除指定个数的value(从左向右执行)
使用场景:
可以作为消息队列或者栈来使用(lpush,lpop)
数据结构
- List 的数据结构为快速链表 quickList。
- 首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。
- 当数据量比较多的时候才会改成 quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next。
- Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
Set
set的许多功能和list相似,区别在于set可以自动去重,并且set提供了判断某个元素是否在set集合内的接口。底层通过一个value为null的哈希表实现,是一个无序集合。
方法:
sadd key v1 v2 v3 :给set中添加元素smembers key :获取指定set中的所有值
sismember key val :判断指定set中是否存在该value,存在返回1,不存在返回0
scard key :返回指定set中元素个数
srem key v1 v2 :删除指定set中的指定元素
spop key :从set中**随机**取出一个值
sinter key1 key2 :返回两个集合的交集
sunion key1 key2 :返回两个集合的并集
sdiff key1 key2 :返回两个集合的差集
差集使用场景:
抽奖(spop);共同好友/推荐好友(sinsert)
Hash
set其实就是hash的简化,hash特别适合用于存储对象,
方法:
hset key field value :给指定的hash中的field键赋value(**注:这里的field就是hash的key-value中的key**)
hset key f1 v1 f2 v2 f3 v3 :对指定hash进行批量的键值对赋值hget key field :从指定hash的指定field中取出value
hdel key field :删除指定hash的指定field
hexits key field :查看指定hash的指定field是否存在hkeys key :列出指定hash中的所有field
hcals key :列出指定hash中的所有值
hincrby key field increment :为指定hash的指定field的value值加上增强
increasement
使用场景:
用于经常需要变更的数据(redis的hash不能使用覆盖,只能先hdel再hset);同时更适用于对象的存储
Zset
可以说是redis中最复杂的一种数据类型,和set相似,是一个没有重复元素的集合,不同之处在于集合中的每个成员都关联了
一个评分(score) ,集合中的元素按照分数从低到高排序,所以是一个有序集合。支持范围查找。
方法:
zadd key score1 v1 score2 v2... :将多个值和对应分数添加到指定zset集合中(无法添加相同分数相同value的元素;添加相同value不同分数的元素,后添加的分数会覆盖先添加的分数;允许添加相同分数不同value的元素)
zrange key in1 in2 (withscore) :返回下标[in1,in2]之间的元素,如果带有withscore
则连带分数一同返回
zrangebyscore key min max (withscore) :返回分数在[min,max]之间的元素(从小到大排列)
zrevrangebyscore key min max (withscore) (limit offset count) :同上,返回从大到小的排列
zincrby key increasenebt value :为元素的score加上增量increasement zrem key value :删除指定zset下指定的value
zcount key min max :统计指定zset下分数在[min,max]之间的元素个数zrank key value :返回该值在集合中的排名,索引从0开始
使用场景:
存储成绩表;存储工资表;排行榜
Redis相关
Jedis(java连接Redis) Jedis 是Redis官方推荐的java连接开发工具连接过程:
0. 在 pom.xml 文件中导入Jedis相关依赖jar包
0. 连接redis数据库:
使用 Jedis jedis=new Jedis("127.0.0.1",6379); 进行连接,其中传入的参数是目的主机的ip地址和端口号
3. 操作数据库:
通过 jedis.set(key,value); 和 jedis.get(key); 进行操作
Redis事务
定义:
Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化,按照顺序执行。事务在执行过程中,不会被其他客户端发送来的命令请求打断
作用:
串联多个命令防止被其他命令打断(其实就是批量执行指令的功能)命令:
multi开始事务exec执行事务
discard取消事务:执行取消事务命令后,事务队列中的所有命令都不会执行
在 multi 和 exec 中的命令,不会被直接执行,先加入任务队列,等到exec执行事务时才会开始批量执行
在执行事务时,如果出现编译期异常,所有命令都不会执行;如果出现运行期异常,只有错误命令不会执行,其他命令正常执行
监视:
redis中使用 watch key1 key2... 来保证事务的安全性
如果一个线程在执行事务之前,发现被 watch 监视的 key 已经被其他线程中的事务修改,则取消本事务操作
执行失败后,要先使用unwatch命令对被监视对象接触监控,之后再次进行监控执行事务
Redis持久化
Redis是内存数据库,如果不将内存中的数据保存到磁盘中,那么一旦服务器进程退出,内存中的数据也会消失,所以Redis提供了持久化功能
Redis提供了两种不同形式的持久化方式:
RDB(Redis DataBase) :
在指定的时间间隔内将内存中的数据集快照(存储的是数据)写入磁盘,恢复时将快照文件直接读到内存里。
数据备份执行过程:
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,
再用这个临时文件替换上次持久化好的文件。整个过程中,主进程不进行任何IO操作,确保了极高的性能。
如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB方式要比AOF方式更加的高效。
RDB的缺点是最后一次持久化后的数据可能丢失。配置文件中默认使用RDB,一般不需要修改。
fork过程
fork()过程会产生一个和父进程完全相同的子进程,子进程多会在事务中被调用,出于效率考虑,子进程引入了"写时复制"技术(并不是
边写边复制,而是要写入的时候再复制),一般情况下父进程和子进程会公用一段物理内存,只有当需要持久化时,才会将父进程的内
容复制一份给子进程。rdb文件的保存策略
rdb保存的文件默认文件名是 dump.rdb ;默认存储在redis的启动目录下;在redis启动时会自动检查启动目录下的dump.rdb文件,并恢复其中的数据
rdb过程的触发策略
0. 通过在 redis.conf 中配置 save 触发:如: save 60 5 意为在60s内修改了5次key就会触发rdb过程
0. 执行 flushall 命令会触发rdb
0. 退出redis也会触发rdb
优缺点
优点:适合大规模的数据恢复;对数据的完整性要求不高
缺点:rdb策略需要一定的时间间隔,如果redis意外宕机了,最后一次修改的数据就会丢失;fork进程会占用一定的内存空间
AOF(Append Only File) :
以日志的形式记录每个写操作,将redis执行过程中的所有写指令记录下来(存储的是指令),只追加文件但不可以改写文件。
Redis启动时会读取该文件并重构数据,换言之,Redis在启动时会根据日志文件的内容,将写指令从前到后执行一次以完成数据的恢复
aof文件保存策略
aof保存的文件默认文件名是 appendonly.aof ,默认不开启,需要手动更改配置文件中的
appendonly 为 yes
aof过程的触发策略
0. 同样在 redis.conf 中进行配置, appendsync always ,表示每次redis的写入都会like
记录到日志(不会产生数据丢失,但占用性能严重)
2. appendsync everysec ,每秒记录到日志一次,如果产生宕机,最后一秒的数据会丢
失
3. appendsync no ,从不主动进行写入,将写入的时机交给操作系统
aof的重写策略
aof是一个累增的文件,当aof文件大于64M时,会fork一个新进程,对aof文件进行重写,重写时检查数据库,重写为 最小指令集
优缺点
优点:备份机制更健全,丢失数据概率更低;日志文本可读缺点:相比于rdb更占用磁盘空间
Redis的主从复制
定义:
主从复制,是指将一台服务器中的数据,复制到其他服务器。前者称为主节点,后者称为从节点,数据是单向复制的,只能由主节点复制到从节点,
默认情况下,每台redis服务器都是主节点,一个主节点可以有0个或多个从节点,一个从节点只能有一个主节点。
用处:
0. 数据备份:主从复制实现了数据的热备份,可以防止数据丢失
0. 故障恢复:当主节点发生故障时,从节点可以代替主节点提供服务
0. 负载均衡:主从复制可以配合读写分离,主节点进行写操作,从节点进行读操作,多个节点分担负载,减少单个服务器压力,提高并发量
0. 主从复制还是哨兵模式和集群能够实施的基础配置:
主从复制只需要对从节点的数据库进行配置单独服务器配置:
修改想要设置为从节点服务器的端口号;pid名字;log文件名;dump,rdb名(在redis.conf中配置)
主从关系配置:
通过指令 slaveof ip port ,在从机中配置,其中ip和port端口号分别为主机ip和端口号,将该服务器设置为指定主服务器的从服务器,临时关系,关闭服务器后关系小时;也可以在redis.conf 中修改 slaveof 改为永久的主从关系
注:可以通过info replication查看主从复制的相关信息,主服务器能读能写,从服务器只有读的功能,主机中的所有数据,都会自动在从机中保存
复制原理:
0. 从机配置连通后,都会给主机发送sync指令
0. 主机立刻进行存盘操作,发送RDB文件给从机
0. 从机收到RDB文件后,进行全盘加载(复制主机内容)
0. 之后每次主机的写操作,都会立刻发送给从机,从机进行加载
薪火相传:
一台从机可以作为另一台服务器的主机(去中心化),当该重机的主机宕机后,该从机可以作为主机支持整个网络的服务
Redis哨兵模式
通过后台监控主机是否发生故障,如果主机发生故障则根据投票数自动选取从机作为主机
配置启动哨兵
哨兵是一个独立的进程,作为进程他会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
在服务器自定义的 myredis 目录下新建 sentinel.conf 文件,在配置文件中填写内容:
sentinel monitor mymaster ip port num
其中myredis是监控对象的服务器名称,num为至少有多少个哨兵同意才开始选定新的主机配置完成后执行如下指令启动哨兵:
redis-sentinel /myredis/sentinel.conf
哨兵模式执行原理
0. 在发生故障而下线的主服务器的所有从服务器里挑选一个从服务器,将其转换成主服务器
选择优先级靠前的(优先级在配置文件中配置 slave-priority n )选择偏移量最大的(偏移量是指获得原主数据最多的)
选择 runid 最小的(每个redis实例启动后都会随机生成一个40位的 runid )
2. 挑选出新的主服务器之后,sentinel向原主服务器的从服务器发送slaveof新主服务器命令
2. 当之前出现故障的原主服务器重新上线时,sentinel会向其发送slaveof命令,让其成为新主服务器的从服务器
Redis集群
定义:
将多个redis服务放在一起,通过某种配置或策略让他们各司其职,形成redis集群作用:
redis集群实现了对redis的水平扩容:即启动N个redis节点,将整个数据库中的数据分布存储在这N个节点中,每个节点存储总数据量的1/N
redis集群通过分区来提供一定能程度的可用性:即集群中的一部分节点失效或者无法进行通信,集群也可以继续处理命令请求
redis集群的配置:安装ruby环境:
yun install ruby
yun install rubygems
拷贝 redis-3.2.0.gem 到 /opt 目录下
在opt目录下执行 gem install --local redis-3.2.0.gem在 redis.conf 配置文件中更改配置
cluster-enabled yes ,打开集群模式
cluster-config-file <集群中redis节点的配置文件名
cluster-node-timeout <time ,进行主从切换设置集群中节点的失联时间,超过该时间,集群自动
整合redis节点,形成集群:
cd /opt/redis-5.0.8/src,切换到redis的安装目录下的src下
执行: ./redis-trib.rb create --replicas 1 ip1 port1 ip2 port2... ,其中ip和port分别为要键入集群的redis服务器的ip地址和端口号
以集群的方式进入客户端 redis-cli -c -p port