目录
NoSQL概述
使用NoSQL的原因
单机MySQL的瓶颈
数据量的总大小一台机器放不下
数据的索引一台机器内存放不下
访问量(读写混合)一个实例不能承受
架构演变
使用缓存技术来缓解数据库的压力(垂直拆分)
使用主从复制技术来达到读写分离
分库分表+水平拆分+mysql集群(分区分库分表)
产生原因
NoSQL数据库的产生是为了解决大规模数据集合多重数据种类带来的挑战。
NoSQL具有非常高的读写性能
NoSQL数据库的四大分类
KV键值
文档型数据库(bson格式比较多)
列存储数据库
图关系数据库
分布式数据库中CAP原理CAP+BASE
C:Consistency(强一致性)
A:Availability(可用性)
P:Partition tolerance (分区容错性)
一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性,最多只能同时较好的满足两个
分区容错性是我们必须要实现的,只能在一致性和可用性之间权衡,大多数网站架构选择的是AP,CP Redis,MongoDB
BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低的解决方案
基本可用(Basically Available)
软状态(Soft state)
最终一致(Eventually consistent)
它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上的改观。
Redis
概述、功能及特点
是完全开源免费的,用C语言编写的,遵守BSD协议。
是一个高性能的key/value分布式内存数据库,基于内存运行
并支持持久化的NoSQL数据库,也称数据结构服务器
特点:
功能:
Redis默认有十六个数据库
Select命令切换数据库
Dbsize查看当前数据库的key的数量
Flushdb:清空当前库
Flushall:通杀全部库
统一密码管理:16个库都是同样的,密码
Redis索引都是从零开始
Redis的五大常用类型及Redis键
Redis键(key)
常用命令
keys * :查看所有key
exists key:的名字,判断某个key是否存在,1表示有,0表示没有
move key db : 移动key
expire key 秒钟:为指定的key设置过期时间
ttl key:查看还有多少秒过期,-1表示永不过期,-2表示已过期
type key:查看你的key是什么类型
String(字符串)
概述
最基本的类型
二进制安全,意思是redis的string可以包含任何数据,比如jpg图片或者序列化对象
字符串value最多可以是512M
常用命令
set/get/del/append/strlen : 添加/获取/删除/向后添加/获取value字符串长度
Incr/decr/incrby/decrby : 增加1/减小1/增加一个指定数字/减小一个指定数字(一定要是数字才能进行加减)
getrange/setrange : 获取指定区间范围内的值(从零到负一表示全部)/设置指定区间内的值(格式:setrange key值 起始位 具体值)
setex(set with expire)键 秒 值/setnx(set if not exist) :设置key的存在时间/如果key没值再设值
mset/mget/msetnx : 多个添加/多个获取/多个判断是否存在设置(要么都成功要么都失败)
Hash(哈希)
概述
是一个键值对的集合
是一个String类型的field和value的映射对象
KV模式不变,但V是一个键值对
常用命令
hset/hget/hmset/hmget/hgetall/hdel : 新增/获取/多个新增/多个获取/获取所有/删除
hlen :哈希长度
hexists key :判断在key里面的某个值的key是否存在
hkeys/hvals : 获取所有的key值/获取所有的value值
hincrby/hincrbyfloat : 增长一个整数/增长一个小数
hsetnx : 不存在时插入
List(列表)
概述
底层实际上是个链表
常用命令
lpush/rpush/lrange : 左边插入列表/右边插入列表/通过范围获取列表值
lpop/rpop : 每次出一个栈顶元素/每次出一个栈尾元素
lindex : 按照索引下标获取元素(从上到下)
llen : 获取列表长度
lrem : 删N个value
ltrim key 开始index 结束index : 截取指定范围的值后再赋值给key
rpoplpush 源列表 目的列表 : 源列表尾部到目的列表头部
lset key index value :给指定索引设置值
linsert key before/after 值1 值2 :把值2插入到值1的前或后
Set(集合)
概述
无序集合,通过HashTable实现
常用命令
sadd/smembers : 集合添加/集合成员
scard :获取集合里面的元素个数
srem key value :删除集合中的元素
srandmember key 某个整数(在一个set里随机出几个数)
spop key :随机出栈
smove key1 key2 在key1里的某个值:将key1中的某个值赋值给key2
sdiff/sinter/sunion :差集(第一个有第二个没有的元素)/交集/并集
Zset(sorted set:有序集合)
概述
每个元素都会关联一个double类型的分数
redis通过分数来为集合中的成员进行从小到大的排序,zset的成员是唯一的,但分数是可以重复的
常用命令
zadd/zrange/ zrange key 起始值 终止值 :加入元素/按范围查找/按范围查找时加上分数
zrangebyscore key 开始score 结束score :通过分数查找
zrem key 某score下对应的value值 : 删除元素
zcard/zcount key score区间/zrank key values值/zscore key 对应值,获得分数 :统计数目/统计区间内的数目/获取下标值/获取分数
zrevrank key values值:逆序获得下标值
zrevrange:逆序获得值
zrevrangebuscore key 结束分数 起始分数 : 通过范围获取值
Redis的持久化
RDB(Redis DataBase)
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复是是将快照文件直接读到内存里。
Redis 会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化进程都结束了,再用这个临时文件替换上次持久化好的文件
如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。RDB的缺点是最后一次持久化后的数据可能丢失。
Fork:Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。(但是会消耗系统资源)
Rdb保存的是dump.rdb文件
默认save写操作次数
1分钟内改了10000次
或5分钟内改了10次
或15分钟内改了1次
如何触发RDB快照
配置文件中默认的快照配置
命令save或者bgsave(save时只管保存,其他不管,全部阻塞;BGSAVE:Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求)
执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义
优势:适合大规模数据恢复,对数据完整性和一致性要求不高
劣势:在一定时间间隔做一次备份,所以如果redis以外down掉的话,就会丢失最后一次快照后的所有修改了;Fork的时候,内存中的数据被克隆了一份,大致两倍的膨胀性需要考虑
AOF(Append Only FIle)
以日志形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取改文件重新构建数据,换言之,redis重启的话就根据日志文件的内容,将写指令从前到后执行一次以完成数据恢复工作。
AoF保存的是appendonly.aof文件
AOF启动/修复/恢复
AOF重写机制
Redis事务
概述
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞。
Redis事务命令
Redis部分支持事务:语法错误直接报错,所有执行失败;运行时出错,则正确的执行,错误的命令报错。
Watch监控
乐观锁悲观锁和CAS(Check And Set)
悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到他拿到锁。传统的关系型数据库里面就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁:每次去拿数据的时候都认为被人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。乐观锁提交版本必须大于记录当前版本才能执行更新。
watch先监控再开启multi,保证两笔金额变动在同一个事务内
一旦执行了exec之前所有的监控锁都被取消掉了
Redis的发布和订阅机制
概述
进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
命令
Redis的主从复制
概述
主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slaver以读为主。
主要用于读写分离和容灾恢复。
用法
配从不配主
从库配置:slaveof 主库IP 主库端口(每次与master断开之后,都需要重新连接,除非配置进redis.conf文件)
配置redis.conf
- 开启daemonize yes
- 修改pid文件名字
- 指定端口
- 指定Log文件名
- Dump.rdb名字
常用的三种方法
一主二仆:
只有主机能写,从机只能读
从机在主机down了之后依旧待命
薪火相传:
上一个Slave可以是下一个slave的Master,Slave同样可以接受其他slaves的连接和同步请求,那么该slave作为了链条中下一个master,可以有效减轻master的写压力。
中途变更转向:会清除之前的数据,重新建立拷贝最新的。(保证数据的有效和完整)
Slaveof 新主库IP 新主库端口。
反客为主:
SLAVEOF no one :使当前数据库停止与其他数据库的同步,转成主数据库。
复制原理
- slave启动成功连接到master后会发送一个sync命令
- master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕后,master将传送整个数据文件到slave,以完成一次同步。
- 全量复制:slave服务在接受到数据库文件数据后,将其存盘并加载到内存中。(首次同步)
- 增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步。(之后变更数据)
- 但是只要是重新连接maser,一次完全同步(全量复制)将被自动执行。
哨兵模式(sentinel)
反客为主的自动模式,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转为主库。
如果之前的master重启回来,不会双master冲突,而是直接变为slave。
Java操作Redis
常见API
连接到 redis 服务
实例
import redis.clients.jedis.Jedis;
public class RedisJava {
public static void main(String[] args) {
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
//查看服务是否运行
System.out.println("服务正在运行: "+jedis.ping());
}
}
编译以上 Java 程序,确保驱动包的路径是正确的。
连接成功
服务正在运行: PONG
Redis Java String(字符串) 实例
实例
import redis.clients.jedis.Jedis;
public class RedisStringJava {
public static void main(String[] args) {
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
//设置 redis 字符串数据
jedis.set("runoobkey", "www.runoob.com");
// 获取存储的数据并输出
System.out.println("redis 存储的字符串为: "+ jedis.get("runoobkey"));
}
}
编译以上程序。
连接成功
redis 存储的字符串为: www.runoob.com
Redis Java List(列表) 实例
实例
import java.util.List;
import redis.clients.jedis.Jedis;
public class RedisListJava {
public static void main(String[] args) {
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
//存储数据到列表中
jedis.lpush("site-list", "Runoob");
jedis.lpush("site-list", "Google");
jedis.lpush("site-list", "Taobao");
// 获取存储的数据并输出
List<String> list = jedis.lrange("site-list", 0 ,2);
for(int i=0; i<list.size(); i++) {
System.out.println("列表项为: "+list.get(i));
}
}
}
编译以上程序。
连接成功
列表项为: Taobao
列表项为: Google
列表项为: Runoob
Redis Java Keys 实例
实例
import java.util.Iterator;
import java.util.Set;
import redis.clients.jedis.Jedis;
public class RedisKeyJava {
public static void main(String[] args) {
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
// 获取数据并输出
Set<String> keys = jedis.keys("*");
Iterator<String> it=keys.iterator() ;
while(it.hasNext()){
String key = it.next();
System.out.println(key);
}
}
}
编译以上程序。
连接成功
runoobkey
site-list