1
.架构演变
-
单机Mysql
-
-
缓存+垂直拆分
-
-
主从复制,读写分离
-
-
分库分表,水平拆分,数据库集群
-
-
当今状态
-
2.NoSQL简介
-
Not Only SQL ,不仅仅是SQL,泛指非关系型数据库
-
NoSQL不依赖业务逻辑存储,而依赖key--value存储,扩展性强
-
不遵循SQL标准,不支持ACID,性能高于SQL
3.NoSQL适用场景
-
对数据高并发的读写
-
海量数据的读写
-
数据高可扩展性
4.NoSQL不适用的场景
-
需要事务支持
-
基于sql的结构化查询存储,处理复杂的关系,需要条件查询
5.常用的NoSQL数据库
-
Memcached
-
数据存储在内存中,一般不持久化
-
支持简单的key-value模式,只支持字符串
-
一般是作为 缓存数据库辅助持久化的数据库
-
使用多线程+锁的技术
-
-
Redis
-
几乎覆盖了Memcached的绝大部分功能
-
数据都在内存中,支持持久化,主要用作备份恢复
-
吃了支持简单的key-value模式,还支持多种数据结构
-
一般作为 缓存数据库辅助持久化的数据库
-
使用单线程+多路IO复用技术
-
-
MongoDB(最接近关系型数据库的非关系型数据库)
-
文档型数据库
-
数据在内存中,数据存储在环形队列中,如果内存不足,数据先进先出。
-
虽然是key-value模式,但是对value(尤其是json)提供把不常用的数据保存到硬盘,并提供丰富的查询功能
-
支持二进制数据和大型对象
-
可以取代RDBMS(关系型数据库),也可以辅助RDBMS
-
-
HBase:Hadoop项目中的数据库
-
Cassandra
-
Neo4j
-
图关系数据库
-
主要描述社会关系,交通图,地图。
-
6.Redis介绍
-
支持String(字符串),list(链表),set(集合),zset(有序集合)和hash(哈希类型),这些类型都支持push/pop, add/remove, 交集,并集,差集等操作,而且这些操作都是原子性的
-
Redis支持各种不同的排序方式
-
Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并在此基础上是西安了master-slave(主从)同步
-
由于其拥有持久化能力和多样的数据结构,可以实现以下操作
-
7.Redis文件介绍
-
Redis-benchmark:性能测试工具,可以在自己本子运行,测试本子性能(服务起来后再用)
-
Redis-check-aof:修复有问题的aof文件
-
Redis-check-dump:修复有问题的dump.rdp文件
-
Redis-sentinel:Redis集群使用
-
redis-server:启动Redis服务端
-
redis-cli:客户端
8.Redis配置
-
修改redis-server后台启动
-
redis配置文件修改:
-
deamonize:yes
-
9.Redis基本命令
-
redis-server:启动redis服务器
-
redis-cli -h 127.0.0.1 -p 6379 : 客户端连接服务器
-
shutdown:关闭服务器
-
exit:退出客户端
-
select index :切换数据库;默认16个数据库,下标从0开始,select 1就会切换进1号库
-
Redis数据库没有用户名,只有一个通用密码。
-
keys * : 查询当前数据库所有的key
-
exists key: 查看当前数据库是否含有key。1表示true,0表示false. map,contsains(key)
-
type key: 查看当前key的类型
-
del key:删除key
-
expire key seconds :为键设置过期时间,单位为秒
-
ttl key:查看还有多少秒过期,-1表示永不过期,-2表示已经过期
-
dbsize :查看当前数据库key的数量
-
flushdb: 清空当前库
-
flushall:清空所有库
10.Redis是单线程+IO
多路
复用技术(重点)
-
IO多路复用技术是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用selec和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回。如果没有,则阻塞直至超时。返回后真正的操作可以在同一个线程内执行,也可以启动线程执行(比如线程池)
-
阻塞IO, 给女神发一条短信, 说我来找你了, 然后就默默的一直等着女神下楼, 这个期间除了等待你不会做其他事情, 属于备胎做法
-
非阻塞IO, 给女神发短信, 如果不回, 接着再发, 一直发到女神下楼, 这个期间你除了发短信等待不会做其他事情, 属于专一做法.
-
IO多路复用, 是找一个宿管大妈来帮你监视下楼的女生, 这个期间你可以些其他的事情. 例如可以顺便看看其他妹子,玩玩王者荣耀, 上个厕所等等. IO复用又包括 select, poll, epoll 模式. 那么它们的区别是什么?
-
select大妈 每一个女生下楼, select大妈都不知道这个是不是你的女神, 她需要一个一个询问, 并且select大妈能力还有限, 最多一次帮你监视1024个妹子
-
poll大妈不限制盯着女生的数量, 只要是经过宿舍楼门口的女生, 都会帮你去问是不是你女神
-
epoll大妈不限制盯着女生的数量, 并且也不需要一个一个去问. 那么如何做呢? epoll大妈会为每个进宿舍楼的女生脸上贴上一个大字条,上面写上女生自己的名字, 只要女生下楼了, epoll大妈就知道这个是不是你女神了, 然后大妈再通知你.
-
11.Redis数据类型
-
String
-
String是二进制安全的。意味着String可以包含任何数据。比如jpg图片或者序列化对象
-
一个Redis中字符串value最多可以是512M
-
Redis的每一个单命令都具有原子性,这是因为Redis是单线程
-
set <key> <value> :添加键值对
-
get <key> :取出key对应的值
-
append <key> <value> :给key对应的v追加value
-
strlen <key> :获得key对应值的长度
-
setnx <key> <value> :只有在key不存在时,设置key的值为value
-
incr <key>:将key中存储的数字值增1,只能对数字值操作,如果为空,新增值为1
-
decr <key>:将key中存储的数字值减1,只能对数字值操作,如果为空,新增值为-1
-
incrby / decrby <key> <步长>:将key中存储的数字值按照步长,增加或减小。
-
mset <key1> <value1> <key2> <value2> ......;同时设置多个key--value对(more set)
-
mget <key1> <key2> ...... 同时获取多个key对应的value
-
msetnx <key1> <value1> <key2> <value2> :只有在所有的key1,key2都不存在时,设置key的值为value
-
getrange <key> <startIndex> <endIndex>;相当于subString(stIndex,endIndex+1) 即[startIndex,endIndex]
-
setrange <key> <startIndex> <value>:用value覆写[startIndex,;;]的值
-
-
setex <key><过期时间> <value>设置键值的同时,设置过期时间,单位秒(set expire)
-
getset <key> <value>:先获取旧值,在设置新值
-
-
List
-
Redis 列表是简单的字符串列表,按照插入顺序排序,可以头插法也可以尾插法
-
List的数据结构是双向列表,对两端操作性能很高,通过索引操作中间节点的性能较差
-
lpush/rpush <key> <value1> <value2>:从左(头)边或右(尾)边把值添加进list
-
lpop/rpop <key> :从左边或右边吐出一个值。值在键在。值光键亡
-
rpoplpush <key1> <key2>:从key1对应的list右边吐出一个值,然后从左边插入key2对应的list中
-
lrange <key> <startIndex> <endIndex>(这里的l表示list):获取元素【startIndex,endIndex】;
-
0表示表头,-1表示表位
-
-
-
lindex <key> <index> 获取key对应的list中索引为index的元素
-
llen <key> 获取列表长度
-
linsert <key> before|after <value> <newValue> 在value之前或之后插入一个新值,
-
lrem <key> <n> <value> 删除n个value
-
n>0:从左向右删除n个value
-
n<0:从右向左删除n个value
-
n=0:表示删除所有value
-
-
-
Set
-
去重无序,可以判断元素是否存在
-
底层是一个value值为null的hash表(map.put("key",null))。所以添加,删除,查找的复杂度都为O(1)
-
sadd <key> <value1> <value2> ... 将多个元素加入到集合
-
smembers <key> 取出集合的所有值
-
sismember <key> <value> 判断集合是否含有value ,没有返回0,有返回1
-
scard <key> 返回集合元素个数
-
srem <key> <value1> <value2> 删除集合元素
-
spop <key> 从集合随机吐出一个元素
-
srandmember <key> <n>从集合随机选出n个值,不删除元素
-
sinter <key1> <key2>求交集
-
sunion <key1> <key2>求并集
-
sdiff <key1> <key2> 求差集 。key1对应的表有,key2对应的表没有。
-
-
Hash
-
类似于Map<String, String>
-
hset <key> <entry.key> <entry.value>:给key对应的hash表,存入一个entry
-
hget <key> < entry.key >:取出entry.key对应的entry.value
-
hmset <key> <entry.key1> <entry.value1> <entry.key2> <entry.value3>批量设置值
-
hexists <key> <entry.key1>:<entry.key1>是否存在
-
hkeys <key> 列出key对应的hash表中所有的entry.key
-
hvals <key> 列出key对应的hash表中所有的entry.value
-
hgetall <key> 列出key对应的hash表中所有的entry
-
hincrby <key> < entry.key > <increment> 即entry.value=entry.value+increment
-
hsetnx <key> <entry.key> <entry.value> 如果entry.key不存在,就增加entry
-
-
zset
-
zset为每个成员都关联了一个评分(score)。这个评分被用来按照从低到高的方式排序集合中的成员,集合成员唯一,但是评分可以重复
-
因为元素有序,所以可以根据评分(score)或者位置(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的、
-
zadd <key> <entry.score1> <entry.value1> <entry.score1> <entry.value1>:添加zset
-
分数不同元素相同,会替换掉zset中原元素的分数,并冲重新排序
-
分数相同元素不同,可以添加进去,并排序
-
-
zrange <key> <startIndex> <endIndex> [WITHSCORES] :返下标[startIndex,endIndex]元素。如果WITHSCORE将连SCORE一起返回
-
zrangebyscore <key> <min> <max> [withscore] [limit offset count] 返回scorez在【min,max】之间的元素(从 小到大排列),limit表示从返回值的第offset个开始,取出count个,
-
zrevrangebyscore <key> < max > < min > [withscore] [limit offset count]返回scorez在【min,max】之间的元素(从 大到小排列),limit表示从返回值的第offset个开始,取出count个,
-
zincrby <key> <increment> <value> 给value元素对应的score加increment
-
zrem <key> <value> 删除元素value
-
zcount <key> <min> <max> 统计分数值在【min,max】间的元素的个数
-
zrank <key> <value> 返回value在集合中的排名(索引)
-
12.Redis配置文件
-
include
-
用于将公共配置提取出来,引入公共配置,编写自己的配置
-
-
IP地址绑定
-
默认只接受本机请求,需要设置以下参数
-
#bind=127.0.0.1
-
protected-mode no
-
-
tcp-backlog
-
可以理解是一个请求到达后至到接受进程处理前的队列
-
backlog队列综合=未完成三次握手队列 + 已经完成三次握手队列
-
高并发环境tcp-backlog的设置值由超时时限内的Redis吞吐量决定
-
-
timeout
-
一个空闲的客户端维持多少秒会关闭,0表示永不关闭
-
-
TCP keepalive
-
对访问客户端的一种心跳检测。每个n秒检测一次,官方推荐60秒
-
-
daemonize
-
是否后台开启
-
-
pidfile
-
每个实例会产生一个不同的pid文件。这里是存放pid文件的位置
-
-
log level
-
日志级别
-
-
logfile
-
日志文件名称
-
-
database
-
设定库的数量,默认16个
-
-
maxclient
-
最大客户端连接数
-
-
maxmemory
-
最大可用内存
-
13.java操作Redis
-
导包
-
< dependency >< groupId >redis.clients </ groupId >< artifactId >jedis </ artifactId >< version >3.3.0 </ version ></ dependency >
-
-
使用
-
Jedis client = new Jedis( "127.0.0.1",6379);client.select(1);System. out.println( client.ping());client.flushAll();client.set( "usr", "yahang");System. out.println( client.get( "usr"));client.close();
-
14.Redis事务
-
Redis事务是一个单独的隔离操作;事务中所有的命令都会按顺序的执行,不会被其他请求所打断
-
Redis事务的主要作用就是串联多个命令防止别的命令插队。就是说把事务中包含的所有命令,打包发给服务器,Redis服务器批量执行完指令,返回结果
-
muti,exec,discard
-
从输入Mutimuti开始,输入的命令都会依次进入命令队列中,但不会被执行,输入exec后,按顺序执行指令
-
可以通过discard来取消事务
-
-
错误处理
-
报告错误: 在muti之后,exec之前,输入的命令有错误,则整个事务取消
-
运行时错误:exec之后,执行命令出错,其他命令照常执行,并不会回滚。
-
-
-
关系型数据库一般是悲观锁,而Redis采用的是乐观锁
-
watch<key1> <key2> <key3> 在muti之前,可以使用watch监视某些键值,如果我在开启事务后,发现监视的键值对,被改动过。则取消事务
-
unwatch 取消监视,如果在unwatch执行之前,exec或discard命令被执行,则自动取消watch
-
代码
-
Jedis client = new Jedis( "127.0.0.1",6379);Transaction tra = client.multi();tra.set( "a", "b");Response<String> result = tra.get( "a");tra.exec();
-
15.Redis持久化
-
Redis提供了两个不同的持久化方式
-
RDB (Redis DataBase):保存数据,节省磁盘空间,恢复快
-
AOF (Append Of File):保存执行的指令
-
-
触发Redis持久化的方式
-
满足保存策略
-
shutdown关闭server
-
手动输入命令save
-
-
RDB
-
在指定时间间隔内将内存中的数据集快照写入磁盘,恢复时直接将快照文件读到内存里。
-
Redis会单独创建(fork 分叉) 一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好了的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效,RDB的缺点是最后一次持久化后的数据可能丢失(意思是如果redis非正常关闭,如kill pid。那么redis 不会持久化,导致之前的修改不会保存)
-
RDB文件保存目录,在配置文件内
-
dbfilename dump.rdb
-
dir ./
-
-
RDB保存策略,在配置文件内
-
save <seconds> <changes> ;在多少秒内完成对数据库的多少次更改就会进行持久化
-
-
手动保存
-
save:只管保存,其他对redis的请求一律阻塞。
-
-
其他配置
-
stop-writes-on-bgsave-error yes :当Redis无法写入磁盘时,直接关掉Redis的写操作
-
rdbcompression yes :进行rdb保存时。将文件压缩
-
rdbchecksum yes :在存储快照时,使用CRC64算法进行数据校验,消耗性能。
-
-
rdb的备份
-
先通过config get dir 查询rdb文件的目录
-
然后将*.rdb文件拷贝到别的地方
-
-
rdb的恢复
-
关闭Redis
-
先把备份的文件拷贝到工作目录下
-
启动Redis, 备份数据会直接加载。
-
-
-
AOF
-
以日志的形式记录每个写操作,将Redis执行过的所有的写操作记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据。也就是说把指令从头到尾执行一遍。
-
默认不开启AOF,更改配置文件开启AOF
-
appendonly yes
-
appendfilename "appendonly.aof"
-
dir ./
-
-
AOF同步频率
-
始终同步:每次Redis的写入都会立刻记入日志
-
每秒同步: 每秒记入日志一次,如果down机,本秒的数据丢失
-
不主动同步,把同步时机交给操作系统
-
配置文件:appendfsync everysec
-
-
Rewrite
-
bgrewriteaof:重写aof中的指令集
-
如果一直写命令,aof会文件会过大,当超过阈值时,会重写aof。根据内存中的内容,自动重写命令。
-
重写aof文件,并没有读写旧的aof文件,而是根据内存中的内容,自动生成命令
-
-
何时重写
-
-
-
如果RDB和AOF同时开启,Redis应该按照加载那个数据文件呢
-
一切以AOF为准
-
16
.主从复制,读写分离
-
什么时主从复制,读写分离
-
-
主机数据更新后根据策略和配置,自动同步到备机。Master以写为主,Slaver以读为主
-
-
配从服务器,不配主服务器
-
拷贝多个redis.conf文件include
-
开启daemonize yes
-
Pid文件名称pidfile
-
指定端口port
-
Log文件名字
-
Dump.rdb名字dbfilename
-
appendonly关掉或者换名字
-
-
示例
-
配置不同的conf文件
-
include .\redis.windows.dafault.conf
-
dbfilename 6379.rdb
-
port 6379
-
-
开启三个redis-sever
-
redis-server redis.windows.6379.conf;redis-server redis.windows.6380.conf;redis-server redis.windows.6381.conf
-
-
info replication:查看当前服务器的主从关系角色
-
-
slaveof <ip> <port>:让本服务器成为某个服务器的备服务器
-
-
通过命令配置的从服务器。一旦重启机器,这种主从关系就不存在了,因此需要在配置文件中保存主从关系。
-
slaveof <masterip> <masterport> 部分版本为 replicaof <masterip> <masterport>
-
-
-
复制原理
-
-
每次从机联通后,都会给主机发送sync同步信号
-
主机立刻进行存盘操作,发送RDB文件给从机
-
从机收到RDB文件后,进行全盘加载
-
之后之主机的每次写操作,都会立刻发送给从机,从机执行相同的操作
-
-
薪火相传
-
-
上一个的slave可以成为下一个服务器的master,向链条一样
-
如果master宕机了,可以对下一个从服务器执行命令。 slaveof no one.下一个从服务器就会变成主服务器
-
风险:一旦中间的slave宕机了,后面的全凉了。
-
-
哨兵模式
-
-
哨兵自动监听主机状态,一旦主机挂掉了,可以自动将从机提升为主机
-
配置哨兵
-
调整为一主二仆
-
新建sentinel.conf文件
-
在配置文件中填写内容
-
sentinel moniter <randomName> <127.0.0.1> <6379> 1
-
其中randomName是为监控对象起的服务器的名字(随便写),1表示:至少有多少个哨兵认为master宕机了,才算宕机。
-
-
启动哨兵
-
redis-sentinel <*.conf>
-
-
-
故障恢复
-
-
-
-
问题
-
切入点问题,假设master已经存了部分数据,slaver才开始运行,slaver会复制master的内容吗
-
主从内容一定是一模一样的,所以会复制
-
-
slaver是否可以写
-
从机只能读不能写,主机可以读可以写
-
-
主机down以后,slaver会上位还是原地待命
-
slaver原地待命,info replication中主机状态显示down
-
-
主机down之后,又开机,新增了部分内容,请问slaver还会和主机一样吗
-
主从内容一定是一模一样的
-
-
从机down了以后,又开机,请问slaver还会和主机一样吗
-
主从内容一定是一模一样的
-
-
17.Redis集群
-
什么是集群
-
Redis集群实现了对Redis的水平扩容。即启动N个redis节点,对整个数据库分布存储在这N个节点中,每个节点存储数据的1/N
-
Redis集群通过分区(Partition)来提供一定程度的可用性(availability):即集群中有一部分节点失效或者无法进行通信,集群也可以继续处理命令请求
-
-
配置集群
-
安装ruby环境
-
配置redis cluster的配置文件
-
拷贝多个redis.conf文件include
-
开启daemonize yes
-
Pid文件名称pidfile
-
指定端口port
-
Log文件名字
-
Dump.rdb名字dbfilename
-
appendonly关掉或者换名字
-
cluster-enabled yes 打开集群模式
-
cluster-config-file nodes-6379.conf 设定节点配置文件名(运行redis-server,自动生成的文件的姓名)
-
cluster-node-timeout 15000 设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换
-
-
按照上述配置制作6个redis-server实例
-
将6个节点合成一个集群
-
组合之前,请确保所有redis实例启动后,node-xxx.conf文件都生成正常
-
./redis-trib.rb create --replicas 1 192.168.44.130:6379 192.168.44.130:6379 ......
-
注意不要用127.0.0.1,使用真实ip地址
-
--replicas 1表示每个master有一个slave
-
-
-
以集群的方式开启客户端
-
redis-cli -c -p 6379 随便选个端口号进去就可以,集群自动进行重定向,选择对应的redis服务器
-
-
cluster nodes 命令查看集群信息
-
redis cluster如何组织这些服务器实例,组成一个集群呢
-
一个集群至少3个master
-
--replicas 1 表示一个master跟随一个slave
-
分配原则尽量保证每个主数据库运行在不同的ip地址,每个从库和主库不在一个ip地址上
-
-
故障恢复
-
如果主节点下线,从节点能否自动升为主节点:可以
-
主节点恢复后,主从关系如何:原主节点变成从节点
-
如果某一段slot的主从节点全down掉,redis集群还能用吗
-
redis.conf中的参数 cluster-require-full-converage yes 表示只有所有slot全部正常,集群才可以提供服务
-
-
-
JedisCluster操作集群
-
//随便从集群的任意一个服务器进去,都可以操作集群HostAndPort hap = new HostAndPort( "192.168.1.1", 6379); //JedisCluster cluster = new JedisCluster( hap);cluster.set( "a", "a");cluster.close();
-
-