一、非关系型数据库:
- 什么是nosql数据库?
Not noly sql,指非关系型数据库。
底层:Nosql数据库不依赖业务逻辑方式存储,而以简单的key—value模式存储
特点:
(1) 不遵循sql标准:因为sql标准依赖于业务逻辑,所以nosql不支持nosql。
(2) 不支持事务的回滚,不支持所有的ACID,仅支持CI。
(ACID:原子性,一致性,隔离性,持久性)
(3) 远超于SQL的性能。
使用场景:
(1) 对数据高并发的读写。
(2) 海量数据的读写。
(3) 对数据高可扩展性的
不适用场景:
(1) 需要事务支持
(2) 基于sql的结构化查询存储,处理复杂的关系,需要即席查询。
2.传统数据库的缺点:
(1) 大数据场景下I/O较高
因为数据是按行存储,即使只针对其中某一列进行运算,关系型数据库也会将整行数据从存储设备中读入内存,导致I/O较高
(2) 修改表结构时,语句的修改会导致锁表,会导致服务不可用。
(3) 存储的是行记录,无法存储数据结构。
(4) 列无法扩展。 - 非关系型数据库memcached与redis的区别?相同点?
相同点:
都是非关系型数据库,数据都在内存中,一般都作为缓存数据库辅助持久化数据库。
区别:
(1) 持久化:memcached不支持持久化,redis支持持久化。
(2) 数据结构:Memcached仅支持简单的key-value模式(string),redis除了支持简单的模式外,还支持多种数据结构的存储,如list,set,hash,zset。
(3) 线程模型:Memcached是多线程+锁,redis是单线程+多路IO复用。
多路IO复用是建立在linux系统上的
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
(3.1)为什么Redis是单线程的
(1)edis是基于内存的操作,CPU不是Redis的瓶颈,瓶颈是内存。
(2)单线程容易实现。 - 非关系型数据库:
(1) MongoDB:文档型数据库,可以根据数据的特点代替RDBMS,成为独立的数据库。或者配合RDBMS,存储特定的数据。(Relational Database Management System)
(2) Memcached:缓存数据库
(3) Redis:缓存数据库
(4) Hbase:列式数据库
(5) Neo4j:图关系数据库
二、Redis数据库
1、 简介:
(1)Redis是一个开源的key-value存储系统。
(2)value有五种数据结构。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。
(3)数据类型支持各种原子性操作。这些数据类型都支持push/pop、
add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。
(4)会定期将缓存中的数据写入磁盘。
2.应用场景:
(1)配合关系型数据库做高速缓存。
(2)由于拥有持久化能力,利用多样性的数据结构存储特定的数据。
3.Redis的底层编写语言:C语言
4、redis安装:
安装redis之后,自动就配置了环境变量,即安装之后,启动redis的命令可以任意在哪个目录下敲都可以。
再加上5中的启动命令,可以看出,只要启动的时候,加上配置文件,无论配置文件在哪,就可以启动不同的redis。
5.linux命令:
Redis服务器启动命令:redis-server
客户端,操作入口:redis-cli
启动命令:redis-server /myredis/redis.conf(注:这个文件夹是自己从redis的安装目录下复制的.conf文件自己创建的)
单实例关闭:redis-cli shutdown
多实例关闭,指定端口关闭:redis-cli –p 6379 shutdown
6.Redis相关知识
端口默认:6379
默认有16个数据库,类似数组下标从0开始,初始默认使用0号库,使用select切换库,所有的库密码都是一样的,要么都连上,要么都连不上。
7.Redis‘的数据类型
value的五大数据类型
(1)string:和memcached相同,string是最基本的数据类型,一个redis的string最多可以是512M。string类型是数据安全的,意味着redis的string可以包含任何数据,比如jpg图片或者序列化的对象。形式:kv:1比1。除了命令中所有的set,除了setnx,msetnx是在设置的时候没有这个key的情况下才能设置,其他的比如说set,mset,setex,getset是无论有没有这个key,都是重新设置值。
(2)List:底层是双链表。形式:kv:1比N,可有重复,有角标
(3)set:自动排重,相比于list提供判断某个成员在不在set集合内。底层是一个value为null的hash表,所以,增删改的复杂度都是O(1)。形式:1:N,没有重复,随机的。
(4)hash:是一个键值对集合,是一个string类型的field和value的映射表,hash特别适合存储对象,类似于java中的map<string,object>。形式:kv形式:1:N,其中N个,,field可以是任意字段
(5)zset(sorted set):与set不同的地方在于,所有都关联了一个评分。形式:kv:1:N,其中N个,,score必须是分数,并且zset还可以根据分数进行排序。
8、java的redis客户端:jedis。
9、redis的事务:
(1)定义:Redis事务是一个单独的隔离操作:事务的所有命令都会被序列化,按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
(2)作用:串联多个命令防止别的命令插队。
(3)操作:(watch,unwatch,mutil,exec,discard)
Mutil执行之前,先执行watch key1 [key2]。。。。。。可以监视一个或多个key,如果在事务执行(exec)之前这些key被其他命令所改动,那么这个事务就会被打断。Unwatch取消对key的监视,如果exec或者discard已经被执行过了,就不需要再执行unwatch了,监视的作用就是看这个key有没有在事务编辑的时候被修改。
开始:mutil,这些命令会依次进入命令队列,但是不会执行,直到输入exec后,这个队列里的命令才会依次执行。如果遇到discard就放弃组队。
(4)redis事务错误处理:
(4.1)组队中某个命令出现错误:
1、是组队中,还没有开始执行,也就是操作只输入了mutil。
2、是整个队列所有的操作都会被取消。
(4.2)执行阶段某个命令出现错误:
只有出现错误的命令不会被执行,而其他命令都会被执行,不会回滚。
(5)事务的实现:
事务的实现分为悲观锁和乐观锁。
悲观锁;很悲观。直接锁上,直接防止了冲突的发生。每次拿到数据的时候总是担心别人要修改这些数据,所以拿到数据的时候给它上了一把锁,如果别人想拿到这个数据,就要阻塞直到先拿到锁。传统的关系型数据库的事务里面就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等都是在做操作之前先上锁。
乐观锁:很乐观,在数据提交的时候才会对是否发生冲突进行检验。拿到数据的时候总是觉得别人不会修改这些数据,所以不会上锁,但是这更新的时候,要先判断别人有没有更新这个数据,可以使用版本等机制,也就是说如果拿到数据的时候版本是1.0,在更改数据的之前,被人把数据进行更了,这样版本就变成了1.1,那么这样自己就不能更新了,只能到版本1.1后进行更新操作。Redis就是利用这种所机制实现事务的。
乐观锁并发高性能也很好,悲观锁虽然并发不高,但是他不允许脏读。
(6) 为什么redis没有隔离级别的概念,因为redis开启事务(mutil)之后,无论最后是执行(exec),还是(discard),在中间的操作实际上都是不执行的,他只是一个操作步骤,并没有实际的执行。所以就不存在关系型数据库中的那种如果事务正在进行对a=2,a=a-1的操作时,事务外查询这个事务中操作的数据a,查询的结果比如是a=1,然后这个事务又回滚了,不对a进行操作了,那么现在查a就是2了,两次查询的结果不同。
综上,redis的事务与关系型数据库的事务最本质的区别在于,mysql在写事务操作时,无论这个事务以后有没有执行,这个操作已经做了,这才有的隔离级别的出现;而redis在书写事务的步骤时,实际操作并没有执行,所以它不存在隔离级别的概念,同样,也不存在回滚的说法,因为本身并没有操作。
(7) redis事务的三特性:
单独的隔离操作:事务中所有的命令都会被序列化,按顺序的执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。也就是说事务写好之后,要么不执行,要么一下执行完。在写的时候不执行。
没有隔离级别的概念:详情见(6)
不保证原子性:redis中同一事物中如果一条命令执行失败了,其后的命令仍然会被执行,没有回滚。原因:因为这种执行命令失败的时候,就是我们所说的bug,而这种基本都出现在测试环境下,生产环境没有,redis为了保证其高速性,不进行回滚,因为即使回滚了,也没有用,而且,这种bug是程序员自己造成的,程序是不会解决的。
10、redis的持久化
提供两种形式的持久化:
(1) RDB
本质:将数据集保存快照
在指定的时间间隔内将内存中的数据集快照写入磁盘。注意指定的时间间隔。
RDB的备份如何执行的?
(1.1) Redis会单独创建一个进程(fork)来进行持久化,这个进程会将数据写入的时候,拷贝到一个临时文件中,然后等一个时间间隔,再将这个临时的文件去替换上次持久化的文件。
(1.2) 主进程是不会进行任何IO操作的,因为redis为了保持极高的性能。
(1.3) 但是这种持久化的方式对数据的完整性不敏感,因为RDB是每隔一个时间间隔对数据持久化。如果数据进行在最后一次持久化的时候丢失了,那么最后一次持久化的数据就会丢失。
默认配置文件名称:dump.rdb
手动保存快照:save 和bgsave,建议用bgsave因为save只管保存,其他不管,数据量大的时候会导致堵塞。Bgsave是在后台保存。
优点:
节省磁盘空间。在保存RDB时,用了算法对文件进行压缩。
恢复速度快,因为是从快照中恢复。
缺点:
比较消耗性能。因为fork使用的时候采用的是写时拷贝技术,但是如果数据量大的时候会比较消耗性能。
备份的时候,如果此时redis意外挂掉了,就会丢失最后一次快照里修改的内容。
(2) AOF
本质:通过日志的形式将所有写的操作记录下来,保存的是操作。
在redis启动时,就会根据日志再重新构建数据。
默认是关闭的
问:AOF和RDB同时开启,redis会听谁的?
会听AOF的,因为RDB有可能会数据不完整,而AOF数据一定是完整的。
重写:当文件大小大于一定的值(默认为64M)时,某几条指令用一条指令代替。重写之后,这个文件就变小了。
如何实现重写?
和快照相类似,旧的文件不动,复制出一个新的文件,对新的文件进行重写,然后用新的文件代替旧的文件。
关系型数据库:悲观锁?redis:乐观锁,因为是乐观锁,所以可以执行watch,都可以看,在执行完之前
优点:
备份机制更稳健,丢失数据的概率比较低。
他的日志文件是可读的。
缺点:
比RDB占用更多的磁盘空间。
恢复备份速度更慢。因为是将之前的操作重新走一遍。
每次读写都同步的话,有一定的性能压力。
存在个别bug,会造成恢复不成数据。
(3) 用哪个好?
官方推荐两个都启用。
如果对数据不敏感,可以单独使用RDB。
不建议单独使用AOF,因为可能出现BUG,一旦出现BUG,数据不可恢复。
如果只用redis做纯内存缓存使用,可以都不用,因为数据都在关系型数据库中,redis制作缓存数据库使用,里面的数据丢失了话再从关系型数据库中拿就可以了。
10、mysql支持四种隔离级别,oracle支持3种隔离级别。
11、redis集群主从复制
(1)什么是主从复制?
主机数据更新后根据配置和策略,自动同步到备份机的master/slaver机制,master以写为主,slave以读为主。
(2)用处:
读写分离。
容灾快速恢复。
(3)配置:
• 拷贝多个redis.conf文件include
• 开启daemonize yes
• Pid文件名字pidfile
• 指定端口port
• Log文件名字
• Dump.rdb名字dbfilename
• Appendonly 关掉或者换名字
不加粗的文字是修改redis默认的配置文件redis.conf中的
加粗的文字是配置在新建的redis6379.conf中的,配置几台服务器就新建几个文件。具体如下图
(4) 操作
Redis服务器启动后后,进入cli客户端入口。
Info replication 打印主从复制的相关信息
Slaveof 成为某个实例的从服务器
(5) 问题:(一主二仆模式演示)
1 切入点问题?slave1、slave2是从头开始复制还是从切入点开始复制?比如从k4进来,那之前的123是否也可以复制
从头开始复制,可以复制。
2 从机是否可以写?set可否?
不可以写,不可以set
3 主机shutdown后情况如何?从机是上位还是原地待命
没有哨兵模式的时候,原地待命
4 主机又回来了后,主机新增记录,从机还能否顺利复制?
可以。
5 其中一台从机down后情况如何?依照原有它能跟上大部队吗?
不能,必须重新成为从机
(6) 复制原理
每次从机连通后,都会给主机发送sync指令。
主机立刻进行存盘操作,发送RDB文件给从机。
从机收到RDB文件后,进行全盘加载。
之后每次主机进行写操作,都会立刻发送给从机,从机执行相同的命令。
(7) 薪火相传:
意思就是从机后面还可以有从机,相对于下面的从机他是主机,也是用slaveof
如果中途更改转向,就是重新认其他的为主机,那么这个从机之前的数据就会清除,重新建立拷贝最新的。
风险是一旦某个slave宕机了,他后面的从机slave也无法备份了。
(8) 反客为主
如果一个master宕机了,后面的slave可以立刻升为master,而不用做任何修改。
(8.1)手动反客为主:
salveof no one
(8.2)自动反客为主(哨兵模式)
能够后台监控主机是否故障,如果故障,根据投票自动将从库转换为主库。
(8.2.1)配置哨兵:
调整为一主二仆模式
自定义的/myredis目录下新建sentinel.conf文件
在配置文件中填写:
sentinel monitor mymaster 127.0.0.1 6379 1
其中,mymater是为监控对象起的服务器名称,1为至少有多少个哨兵同意迁移的数量。
启动哨兵:执行redis-sentinel /myredis/sentinel.conf
恢复流程:(自动的)
(1) 从从服务器中挑选一个成为主服务器。挑选条件依次为:
1、选择优先级靠前的:优先级在redis.conf中slave-priority 100
2、选择偏移量最大的:偏移量是指获得原主数据最多的
3、选择runid最小的从服务:每个redis实例启动后都会随机生成一个40位的runid
(2)挑选好之后,其他从服务其会自动向主服务器发送slaveof命令
(3)即使之前的主服务器重新上线,也会自动发送slaveof命令成为从服务器。
(4)此时如果再重新启动一台新的服务器,需要手动slaveof才能成为从服务器,而之前的已经在里面的服务器和掉线的服务器不需要手动。
12、redis集群
(1)解决的问题: - 容量不够,redis进行扩容
- 并发写操作
(2)什么是集群:
Redis集群实现对redis的水平扩容,也就是启动N个redis
个节点,将整个数据库分布存储在这n个节点中,每个节点存储总数据的1/N个。
Redis集群通过分区来提供一定成都的可用性,即使集群中有一部分节点失效或者无法通讯,集群也可以继续处理命令请求。
(3)集群配置
(3.1)安装ruby环境:
执行yum install ruby
执行yum install rubygems
(3.2)拷贝redis-3.2.0.gem到/opt目录下
(3.3)执行在opt目录下执行 gem install --local redis-3.2.0.gem
(3.4)制作6个实例,6379,6380,6381,6389,6390,6391
拷贝多个redis.conf文件
开启daemonize yes
Pid文件名字
指定端口
Log文件名字
Dump.rdb名字
Appendonly 关掉或者换名字
说明:同一主二仆
安装redis cluster配置修改
cluster-enabled yes 打开集群模式
cluster-config-file nodes-6379.conf 设定节点配置文件名
cluster-node-timeout 15000 设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换
将六个节点合成一个集群
组合之前,请确保所有redis实例启动后,nodes-xxxx.conf文件都生成正常。
合体:
cd /opt/redis-3.2.5/src
./redis-trib.rb create --replicas 1 192.168.1.100:6379 192.168.1.100:6380 192.168.1.100:6381 192.168.1.100:6389 192.168.1.100:6390 192.168.1.100:6391
通过 cluster nodes 命令查看集群信息
(4) redis cluster如何分配这六个节点
8. 一个集群至少要有三个节点。
9. 选项—replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。这也就是为什么我们没有指定处从节点的个数,而集群启动时,就有3个主节点,3个从节点,因为每个主节点都跟着一个从节点,一共起了6个节点,一定是这样分配的。
10. 分配原则尽量保证每个主数据库运行不同的IP地址,每个从库和主库不在同一个IP地址上。
11. 为什么前三个IP是主节点后3个IP是从节点?应该是系统默认,前面的是主节点。
(5) 什么是slots?
在合体之后最后出现
一个redis集群中包含16384个插槽,数据库中的每个键都属于这16384个插槽的其中一个,根据key的值使用算法算出。
集群中每个节点负责处理一部分插槽。拿3个主节点来说:
节点 A 负责处理 0 号至 5500 号插槽。
节点 B 负责处理 5501 号至 11000 号插槽。
节点 C 负责处理 11001 号至 16383 号插槽。
(6) 在集群中录入值
12. 每次录入都会根据key值计算在哪个插槽,如果不是对应服务器的插槽就会报错。
13. 如果不是对应服务器的插槽,可以在客户端启动时用命令
redis-cli -c -p 6379,加上-c后就实现了重定向,这样即使不是对应服务器的也可以进行插入。
14. 不在一个slot下的键值,不能使用mget,mset等多键操作。
(7) 集群jedis开发
Set set =new HashSet();
set.add(new HostAndPort(“192.168.1.100”,6379));
JedisCluster jedisCluster=new JedisCluster(set);
jedisCluster.set("k1", "v1");
System.out.println(jedisCluster.get("k1"));
通过设置set,将节点的ip都设置进set中,然后new一个JedisCluster进行创建对象。
(8) 集群好处
实现扩容
分摊压力
无中心化配置相对简单
(9) 集群的不足
多键操作不支持
多键的事务不支持
由于集群方案出现的比较晚,所以很多公司采用了其他的集群方案,用的代理或者客户端分片,想要迁移到redis cluster,需要整体迁移而不是逐步过渡,复杂度比较大。
(9.1.3)代理集群至少需要8台服务器,架构
圆圈和小方框是从服务器和主服务器,中间的是代理服务器,一共至少8台
集群架构,一共至少6台
15、分布式和集群
分布式:不同的机器放的是不同的信息。
集群:把所有的信息平均分成几份。