分表分库 + 水平拆分 + mysql集群:
NoSQL用于超大规模数据的存储。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
-键 - 值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- 高性能,高可用性和可伸缩性
- CAP定理
CAP定理:对于一个分布式计算系统来说,不可能同时满足以下三点:
? CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。
? 因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:
NoSQL数据模型:
NoSQL数据库四大分类:
/usr/local/bin/redis-server /opt/myRedis/redis.conf
关闭服务:SHUTDOWN
redis-cli -p 6379;
6379是Redis默认端口 退出:exit 或 ctrl+cRedis默认在redis.conf中配置16个数据库0-15, select 7 :表示使用6号数据库,
set 和 get 能存放和取出数据, 其中set key val 时key已经存在,则覆盖
keys k*
: 查询以 k 开头的键 FLUSH:删除
keys *
:查询所有key,move k 2
:将 k 移动到2号数据库
exists key:判断这个key是否在当前数据库中存在
expire key 1 : 设置key过期时间为1秒
ttl key : 查看还有多少秒过期,-1表示永不过期,-2表示已经过期
type key : 查看key的类型
del key:删除key
redis.conf 默认安装在:/opt/myredis
Units单位:配置大小单位,定义了一些基本的度量单位,只支持bytes不支持bit,对大小写不敏感
INCLUDES:包含其他配置文件,作为总闸
GENERAL:
daemonize yes:启用守护进程。设置redis关掉终端后,redis服务和进程还在执行。
port 6379:默认端口
tcp-backlog 511:配置tcp的backlog ,是一个连接队列,backlog 队列总和=未完成三次握手队列+已经完成三次握手队列,高并发环境下需要一个高backlog 值来避免客户端连接慢问题
timeout 0:设置空闲多少秒后关闭redis连接,0表示一直连接不关闭
Tcp-Keepalive:单位为秒,如果设置为0,则不会进行Keepalive检测,建议设置为60,作用类似心跳检测、判断每过一段时间检测是否还存活、使用中
loglevel debug/verbose/notice/warning :设置log日志级别,从左到右级别依次变高
database 16:设置数据库数量,默认为16
Syslog-enabled:是否把日志输出到syslog中,默认不使用
Syslog-facility:指定syslog设备,值可以是USER或LOCAL0-LOCAL7
SNAPSHOTTING快照(RDB)
REPLICATION复制
SECURITY安全:
LIMITS限制:
APPEND ONLY MODE追加(AOF)
参数说明
redis.conf 配置项说明如下:
1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
daemonize no
2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
pidfile /var/run/redis.pid
3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字
port 6379
4. 绑定的主机地址
bind 127.0.0.1
5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
timeout 300
6. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
loglevel verbose
7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
logfile stdout
8. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
databases 16
9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
save <seconds> <changes>
Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。
10. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
rdbcompression yes
11. 指定本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
12. 指定本地数据库存放目录
dir ./
13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
slaveof <masterip> <masterport>
14. 当master服务设置了密码保护时,slav服务连接master的密码
masterauth <master-password>
15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭
requirepass foobared
16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
maxclients 128
17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
maxmemory <bytes>
18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no
19. 指定更新日志文件名,默认为appendonly.aof
appendfilename appendonly.aof
20. 指定更新日志条件,共有3个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec
21. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)
vm-enabled no
22. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap
23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0
vm-max-memory 0
24. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值
vm-page-size 32
25. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。
vm-pages 134217728
26. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4
vm-max-threads 4
27. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
glueoutputbuf yes
28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
29. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)
activerehashing yes
30. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include /path/to/local.conf
Redis持久化包含RDB(Redis DataBase)和AOF(Append Only File)
RDB:在指定时间间隔内将内存中的数据快照写入磁盘,也就是SnapShot快照,它恢复时是将快照文件直接读到内存里
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。在整个过程中主线程不进行任何IO操作,确保了极高的性能。
如果需要进行大规模数据恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。
RDB的缺点是最后一次持久化后的数据可能丢失
Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是一个全新进程,叫子进程
RDB保存的是dump.rdb文件,命令是:save
可以在任何一个目录下使用redis,所生成的db文件也保存在该目录
一般备份dump.rdb时需要拷贝文件到另外的备机上,以防物理损坏
SHUTDOWN关闭redis的同时,默认会commit并备份到dump.rdb中。slushall命令也会产生dump.rdb,但空文件无意义
如何恢复数据?重启服务后,默认会将启动redis的当前目录下的备份文件dump.rdb 恢复到redis数据库中
手动备份命令:save 或者 bgsave。其中save只管保存,其他不管全部阻塞。BGSAVE:表示redis会在后台异步进行快照操作,快照同时还可以响应客户端请求,可以通过lastsave命令获取最后一次成功执行快照的时间。
config get dir 可以获得快照的备份文件dump.rdb所在目录
优势:适合大规模数据恢复,对数据完整性和一致性要求不高。
劣势:fork时内存的数据被克隆了一份,大致2倍的膨胀性需要考虑内存空间是否足够大。最后一次备份的数据可能丢失
动态停止所有RDB保存规则命令:redis-cli config set save ""。不建议使用
配置文件里的 SNAPSHOTTING快照(RDB)
AOF是在RDB之后产生,是以日志的形式记录每个写操作,将Redsi执行过的所有写指令记录,只需追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据。换言之,redis重启时会根据日志文件的内容将写指令从头到尾执行一次以完成数据的恢复工作
AOF也是启动redis后自动执行日志文件appendonly.aof 从而恢复数据。
/usr/local/bin/redis-server /myredis/redis_aof.conf
:启动Redis服务并以aof文件恢复数据
dump.rdb和 appendonly.aof 可以同时存在,先加载appendonly.aof,若aof文件中有记录是错的,开启redis服务会失败。此时在redis的bin目录下使用命令:redis-check-aof --fix appendonly.aof
可查看appendonly.aof 的错误信息并消除其中的不规范指令,才能启动redis服务
appendonly.aof 因为只追加写操作记录,因此容易内存膨胀,free命令用于查看内存使用情况,df -h 查看磁盘空间
Rewrite:
AOF的重写机制,当AOF文件大小超过所设定的阈值时,会启动AOF文件的内容压缩,只保留可以不恢复数据的最小指令集,可以使用命令bgrewriteaof
原理:AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方法重写了一个新aof文件,类似快照。
触发机制:redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
(优势)对应在redis.conf 的配置:APPEND ONLY MODE追加(AOF)
劣势:相同数据集的数据而言aof文件远大于rdb文件,恢复速度慢于rdb。运行效率也慢,但每秒同步策略效率较好,不同步效率和rdb相同
如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。
如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构
可以一次执行多个命令,本质是一组命令的集合,一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞
能干嘛?开启事务后每个指令都会加入一个队列中,一次性、顺序性、排他性地执行一系列命令
常用命令
若事务块中有无效命令(错误指令)则全部命令不生效,若事务块中都是有效命令但有些命令无法执行成功,则只有这些命令执行失败,其他命令无影响
watch监控
事务3阶段:MULTI开启事务=》命令入队,此时还未被执行=》EXEC执行,触发事务
事务3特性:
进程间的一种消息通信模式:发送者(pub)发布消息,订阅者(sub)接收消息
一次性订阅多个: SUBSCRIBE c1 c2 c3 c*
消息发布: PUBLISH c2 hello-redis
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
使用步骤:
一组sentinel能同时监控多个master
复制的缺点:由于写操作都是现在Master进行,然后同步更新到slave上,所以主库同步到从库有一定延迟,Slave数量增加,延迟会更加严重
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.set("k1", "v1");
System.out.println(jedis.ping());
Set<String> keys = jedis.keys("*");
}
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
Transaction transaction = jedis.multi();
//transaction.discard(); // 事务取消
transaction.exec();
}
public class TestTransaction {
public boolean transMethod() {
Jedis jedis = new Jedis("127.0.0.1", 6379);
int balance;// 可用余额
int debt;// 欠额
int amtToSubtract = 10;// 实刷额度
jedis.watch("balance");
//jedis.set("balance","5");//此句不该出现。模拟其他程序已经修改了该条目
Thread.sleep(7000); // 延时7秒,模拟高并发或网络延迟,在7秒的过程中有其它程序改变了balance
balance = Integer.parseInt(jedis.get("balance"));
if (balance < amtToSubtract) {
jedis.unwatch();
System.out.println("modify");
return false;
} else {
System.out.println("***********transaction");
Transaction transaction = jedis.multi();
transaction.decrBy("balance", amtToSubtract);
transaction.incrBy("debt", amtToSubtract);
transaction.exec();
balance = Integer.parseInt(jedis.get("balance"));
debt = Integer.parseInt(jedis.get("debt"));
System.out.println("*******" + balance);
System.out.println("*******" + debt);
return true;
}
}
/**
* 通俗点讲,watch命令就是标记一个键,如果标记了一个键, 在提交事务前如果该键被别人修改过,那事务就会失败,这种情况通常可以在程序中
* 重新再尝试一次。
* 首先标记了键balance,然后检查余额是否足够,不足就取消标记,并不做扣减; 足够的话,就启动事务进行更新操作,
* 如果在此期间键balance被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中通常可以捕获这类错误再重新执行一次,直到成功。
*/
public static void main(String[] args) {
TestTransaction test = new TestTransaction();
boolean retValue = test.transMethod();
System.out.println("main retValue-------: " + retValue);
}
}
public static void main(String[] args) throws InterruptedException
{
Jedis jedis_M = new Jedis("127.0.0.1",6379);
Jedis jedis_S = new Jedis("127.0.0.1",6380);
jedis_S.slaveof("127.0.0.1",6379);
jedis_M.set("k6","v6");
Thread.sleep(500);
System.out.println(jedis_S.get("k6"));
}
public class JedisPoolUtil {
private static volatile JedisPool jedisPool = null;//被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存。
private JedisPoolUtil() {} // 单例模式,构造方法私有化,无法new该实例对象
public static JedisPool getJedisPoolInstance() // 对外提供获得单实例JedisPool的方法
{
if(null == jedisPool)
{
synchronized (JedisPoolUtil.class) // 单例模式的双重校验锁
{
if(null == jedisPool)
{
JedisPoolConfig poolConfig = new JedisPoolConfig();
// pool可分配的jedis实例,pool.getResource()获取;如果为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态exhausted。
poolConfig.setMaxActive(1000);
// 控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
poolConfig.setMaxIdle(32);
// 表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛JedisConnectionException;
poolConfig.setMaxWait(100*1000);
// 获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;
poolConfig.setTestOnBorrow(true);
jedisPool = new JedisPool(poolConfig,"127.0.0.1");
}
}
}
return jedisPool;
}
public static void release(JedisPool jedisPool,Jedis jedis)
{
if(null != jedis)
{
jedisPool.returnResourceObject(jedis);
}
}
原文:https://www.cnblogs.com/JayV/p/13311334.html