NoSQL

NoSQL

1 为什么使用NoSQL
1)单机MySQL
随着业务发展,可能出现单机mysql存储瓶颈:表内容,索引存储不下。并发访问奔溃等问题
2)缓存memcache+mysql+垂直拆分
根据业务不同,业务分库存储
memcache分布式缓存技术
但是随着业务增长,出现写入瓶颈
3)主从复制,读写分离
数据库读写分离技术:主库负责写入操作,从库负责读取操作。解决了写入瓶颈。
但是随着业务发展,表越写越大。
主从复制原理??????
(1)首先,mysql主库在事务提交时会把数据库变更作为事件Events记录在二进制文件binlog
中;mysql主库上的sys_binlog控制binlog日志刷新到磁盘。
(2)主库推送二进制文件binlog中的事件到从库的中继日志relay log,之后从库根据中继日
志重做数据库变更操作。通过逻辑复制,以此来达到数据一致。
Mysql通过3个线程来完成主从库之间的数据复制:其中BinLog Dump线程跑在主库上,
I/O线程和SQl线程跑在从库上。当从库启动复制(start slave)时,首先创建I/O线程连
接主库,主库随后创建Binlog Dump线程读取数据库事件并发给I/O线程,I/O线程获取
到数据库事件更新到从库的中继日志Realy log中去,之后从库上的SQl线程读取中继日
志relay log 中更新的数据库事件并应用。
4)分表分库+水平拆分+mysql集群
水平拆分:把一张表存储在不同的数据上
mysql集群协同提供服务
5)mysql拓展性瓶颈
a:业务越复杂,mysql优化技术越来越复杂
b:当今业务,大文本本多。关系型数据库处理大文本性能一般
c:关系型数据库,结构固定。拓展能力差。

2 NoSQL
不仅仅是SQL。SQL在web2.0时代暴露了很多问题。NOSQL的产生就是解决大规模数据,集合
多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。 比如google
facebook等,存储的数据不需要固定的模式,无需多余操作就可以横向拓展。
mongodb redis memcache区别?
1)mongodb主要用于 文本数据库,比较类似sql,可以分布式部署。如果只用于文本数据库,
mongodb优于redis。redis目前其“缓存”的性质远大于其“数据存储“的性质。
2)如果只用于分布式缓存,可以选择memcache
3 NoSQL特性
1)易扩展
去掉了关系数据库的关系特性。数据之间无联系,易拓展
在无形之间,在架构层面上带来了可扩展的能力

2)大数据量高性能

              得益于它的无关系型,数据库捡到。nosql具有很高的读写性能,尤其在大数据量下,表 

现仍然优秀(redis每秒读11万,写8万)
3)多样灵活的数据模型
无需事先给要存储的数据建立字段,随时可以存储自定义的数据格式,而在关系数据
库里,增加字段
简直就是噩梦
4)高可用
NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase
模型, 通过复制模型也能实现高可用。
4 RDBMS 和 NOSQL比较
rdbms: nosql:
高度组织化结构化 没有声明性查询语言
结构化查询 没有预定义模式
数据和关系都存储在表中 键值存储,列存储,文档存
储,图形存储
数据操纵语言,数据定义语言 最终一致性,而非ACID
严格的一致性 非结构化和不可预知的数据
基础事务 CAP定理
高性能,高可用,可伸缩

5 NoSQL经典应用

淘宝网 
      1)当下是sql和nosql一起使用 

2)阿里中文站商品信息如何存放
i:商品的基本信息(关系型数据库,淘宝内部使用的mysql是内部改造过的)
ii:商品详情、评价信息(多文字)
文档数据库 mongoDB
iii:商品图片
分布式的文件系统,淘宝有自己的TFS
谷歌GFS
Hadoop的HDFS
vi:商品关键字
ISearch 站内搜索引擎
v:商品的波段性和热点高频信息
某时间段被查询的高频词汇 存储在redis缓存中
vi:商品的交易、价格计算、积分累计
支付宝,第三方内部接口

6 NoSQL数据库的四大分类

1)KV键值
新浪:BerkeleyDB+redis
美团:redis+tair
阿里、百度:memcache + redis
2) 文档数据模型bson
CouchDB MongoDB
3) 列存储数据库
HBase Cassandra
分布式文件系统
4) 图关系数据库
社交网络 推荐系统 构件关系图谱
Neo4J InfoGrid

7 分布式数据库中CAP原理 CAP+BASE

      i:传统的ACID

Atomicity
Consistency
Isolation
Durability

ii:NoSQL的是CAP

Consistency 强一致性
Availability 可用性
Partition tolerance 分区容错性
iii:CAP只能三选二
三个特性不能同时满足。最多只能同时满足两个。而在分布式时代,而分区容错性是我们必
须实现的
CA:单点集群,满足一致性,可用性系统,通常在可拓展性上不太强大
CP:满足一致性,分区容忍性的系统,通常性能不是特别高
AP:满足可用性,分区容忍性的系统,通常可能对一致性要求低一点
CA 传统的关系型数据库
AP 大多数网站架构的选择
CP Redis Mongodb
iv:BASE
BASE解决了关系数据库的强一致性导致的可用性降低这个问题。
基本可用 Basically Avaliable
软状态 Soft State
最终一致 Eventually consistent

8 Redis

Redis:(Remote Dictionary Server远程字典服务器)
是完全开源免费的,用C语言编写,遵循BSD协议,是一个高性能的(key/value)分布式内存数
据库
,基于内存运行并支持持久化的NoSQL数据库
Redis和其他(key­value)的缓存产品有以下特点:
一、redis支持数据持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
二、redis不仅支持简单的key­value,同时还提供了list,set,zset,hash等数据结构存储
三、redis支持数据备份,而master­slave模式
Redis能做什么:
内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
取最新N个数据的操作,如:可以将最新的10条评论的ID放在redis的list集合里面
模拟类似于HttpSession这种需要设定过期时间的功能
发布、订阅消息系统
定时器、计数器

redis应用场景

        •   缓存(数据查询、短连接、新闻内容、商品内容等等)
        •   聊天室的在线好友列表
        •   任务队列。(秒杀、抢购、12306等等)
        •   应用排行榜
        •   网站访问统计
        •   数据过期处理(可以精确到毫秒
        •   分布式集群架构中的session分离

9 redis安装

1)下载redis的tar包并解压 
2)进入解压后的命令,官方建议先运行make test 
3)安装tcl 
    sudo yum install tcl 
4) make test通过后,进入到src文件夹下 make install。出现好几个 INSTALL install,说明安装成 


5) 拷贝并修改redis.conf文件,
设置daemonize yes //redis以后台进行运行
6)运行redis
redis­server …/redis.conf
7)检查redis是否启动
ps ­Af | grep redis
8)运行redis命令行客户端
redis­cli ­p 6379
键入命令:
set k1 v1
get k1
flushall
10 安装其他细节
1)默认redis安装16个库,类似数组,可以用下标表示
select 7 //切换到8号库
2)DBSIZE 查看所有key的个数
keys * 查看所有的key是哪些
3)FLUSHDB 清空当前所在库的所有key
FLUSHALL 清空总共16个库的key
4)默认端口6379
11 键 key的命令
redis命令的终极版:redisdoc.com
key *
DBSIZE
key k*
EXISTS k1;//判断是否存在k1
move k3 2;//将k3移到3号库
ttl key 查看还有多少秒过期,­1表示用户过期,­2表示已过期
type key 查看key的类型
expire k3 10 设置k3,10秒后过期
12 redis数据类型
String 字符串
String是redis的基本类型,一个key对应一个value
string类型是二进制安全的,意思是string可以包含任何数据,比如jpg、序列化对象等
string类型字符串value最多是512M
Hash 哈希,类似java中的map
是键值对集合
是一个string类型的field和value的映射表,hash特别适合用于存储对象
类似于Map
List 列表
列表是简单字符串列表,按照插入顺序排序。可以添加元素
在链表的头或者尾部
底层是链表结构

Set 集合
无序集合,通过HashTable实现
Zset 有序集合(sorted set)
和set一样是string类型元素集合,且不允许重复
不同的是每个元素都会关联一个double类型的分数
redis正是通过分数来为集合中的成员进行从小到大的排序
zset的成员是唯一的,但分数却可以重复
13 String数据类型
单键单值
set/get/del/append/strlen
incr/decr/incrby/decrby
getrange/setrange
setex(set wich expire)键秒值/setnx(set if not exist)
mset/mget/msetnx m代表multi
mset k1 v1 k2 v2 k3 v3
mget k1 k2 k3
msetnx k1 v1 k2 v2 //如果k1 或者 k2 有一个存在,全部不会插入
14 List数据类型
单键多值
lpush/rpush/lrange
lpush list01 1 2 3 4 5
rpush list02 1 2 3 4 5
lrange list01 0 ­1
lpop/rpop
lpop test01 左侧弹出
rpop test02 右侧弹出
lindex 按照索引下标获取元素
lindex list01 3
llen 集合长度
llen list01
lrem key N 删除N个value
lrem list01 2 3 从左开始,删除2个3元素
ltrim key m n 截取指定范围的集合并赋值给key
ltrim list01 0 5 //含头含尾
rpoplpush
rpoplpush list01 list02
//list01右侧弹出,从左侧进入list02
lset key index value
lset list01 1 x
//将list01的索引是1的数据设置成x
linsert key before/after
linser list01 before x java
linser list01 after x oracle
//在数据是x的前面插入java
15 Set数据类型
单键多value,且value不重复
sadd/smembers/sismember
sadd set01 1 1 1 2 2 3 3
smembers set01
sismember set01 1 //判断集合中是否有1
scard 获取集合里元素个数
scard set01
srem key value 删除集合中指定元素
srem set01 1
srandmember key n 随机出n个数
srandmember set01 2
spop key 随机出站
spop set01
smove key1 key2 在key1里的某个值赋值给key2
smove set01 set02 5
//将set01中的5放入到set02中
集合操作:
set01: 1 2 3 4 5
set02: 1 2 3 a b
sdiff 差集
sdiff set01 set02
sinter 交集
sinter set01 set02
sunion 并集
sunion set01 set02
16 Hash数据结构
KV模式不变,但是value是键值对
hset/hget/hmset/hmget/hgetall/hdel
hset user id 11
hget user id
hset user name zhangsan
hget user name
hmset customer id 11 name lisi age 20
hmget cutomer id name age
hmgetall customer
hdel user name
hlen
hlen user
hexists key
hexists customer id
hexists customer email
hkeys/hvals
hkeys customer 获取所有的key
kvals customer 获取所有的values
hincrby/hincrbyfloat
hincrby customer age 2
hset customer score 8.0
hincrbyfloat customer age 0.5
hsetnx
hsetnx customer score 10.0
17 Zset数据结构
有序集合set
在set基础上,加上score值
之前set: k1 v1 v2 v3
现在set:k1 score v1 k2 score v2
zadd/zrange
zadd set01 60 v1 70 v2 80 v3 90 v4 100 v5
zrange set01 0 ­1
zrange set01 0 ­1 withscores
zrangebyscore key m n
zrangebyscore set01 60 90
//取出score是指定区间的集合元素,大于等于60 小于等于90
zrangebyscore set01 60 (90
//取出score是指定区间的集合元素,大于等于60 小于90
zrangebyscore set01 (60 (90
//取出score是指定区间的集合元素,大于60 小于90
zrangebyscore set01 60 90 limit 2 2
//类似于mysql的分页,从第二个数据,往后去除两条
zrem key
zrem set01 v5
//删除值是V5的元素
zcard/zcount key score 区间/zrank key values值
zcard set01
//统计集合中的个数
zcount set01 60 80
//统计score是60~80之间的个数
zrank set01 v4
//获取指定值的索引
zscore set01 v4
//获取v4值得score
zrevrank key value
zrevrank set01 v4
//逆序获取指定值的 索引值
zrevrange
zrevrange set01 0 ­1
//逆序输出集合元素
zrevrangebyscore
zrevrangebyscore set01 90 60
//输出90 ~60score的元素

redis持久化

1 RDB

Redis DataBase
官网介绍:
在指定的之间间隔内将内存中的数据集快照写入磁盘。也就是行话将的Snapshot快照,它恢复时是将快照文件直接读到内存中。

RDB是什么?
Redis会单独创建(fork)一个子进程来进行持久化,它先将数据写入到
一个临时文件中,持久化过程结束时,再用这个临时文件替换上次持久化
好的文件。
整个过程中,主进程时不进行任何IO操作的,这就确保了极高的性能
如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是非常敏感
那么RDB方式要比AOF方式更加高效,
RDB的缺点是最后一次持久化后的数据可能丢失

Fork
作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序
计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程

RDB保存的是dump.rdb文件

配置文件位置
在配置文件中的 :SNAPSHOTTING

以下三者条件之一,就会触发rdb操作:

a 900秒,至少有一个key修改过后
b 300秒后,当至少10个key改变后
c 60秒后,至少10000个key改变

恢复dump.rdb
重启redis,会重新将dump.rdb文件中的
数据读入redis内存中

flushall shutdown 会直接刷新dump.rdb

save命令可以直接触发rdb
stop-write-on-bgsave-error 默认是yes,表示如果后台redis出错,前台就停止写入.也可以配置成no,表示不在乎数据不一致
或者有其他的手段发现和控制

rdbcompression 默认是yes,redis会采用LZF算法进行压缩。如果不想消耗CPU进行压缩,可以设置为no进行关闭

rdbchecksum 默认值是yes,在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是会增大10%的性能消耗,如果希望提升性能,可以关闭

触发快照备份条件:
1)配置文件默认配置
2)save 或者 bgsave(后台异步进行快照备份)
save时只管保存,其他不管,全部阻塞
bgsave后台异步进行快照操作,快照同时还可以相应客户端请求
3)flushall 也会立即备份,但是无意义
4)shutdown 也会立即触发rdb

优势:
适合大规模数据恢复
对数据完整性和一致性要求不高

劣势:
在一定间隔时间做一次备份,所以如果redis意外宕掉,就会失去最后一次快照后的所有修改。fork时,内存中的数据被克隆了一份,2倍的膨胀性需要考虑

停止rdb:
有些情况下,我们只想利用Redis的缓存功能,并不像使用 Redis 的持久化功能,那么这时候我们最好停掉 RDB 持久化。
方式一:
可以通过上面讲的在配置文件 redis.conf 中,可以注释掉所有的 save 行来停用保存功能或者直接一个空字符串来实现停用:save “”
方式二:
redis-cli config set save “”

2 AOF

Append Only File

AOF是什么?
以日志的形式来记录每个写操作。将redis执行的所有写指令记录下来(不记录读),只许追加文件不可以改写文件,
redis启动之初会读取该文件重新构建数据。换言之,redis重启的话就根据日志文件的内容将写指令从前往后执行一次来完成数据的恢复工作

Append Only Mode
默认是关闭状态。
appendonly yes
appendfilename “appendonly.aof”

aof和rdb可以是共存关系,二者相辅相成。如果aof文件因为外因损坏,再次启动redis会启动不起来,如果rbn和aof并存,默认是按照aof启动。此时,使用redis-check-aof --fix appendonly.aof 来进行aof的文件修复。修复后,可以正常启动

appendfssync:
always 同步持久化 每次发生数据变更会立即记录到磁盘,性能较差,数据完整性较好
everysec 出厂默认推荐,异步操作,每秒纪录 如果一秒内宕机,则有数据丢失
no

rewrite
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制(优化为最小指令集)。当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof

重写原理:AOF文件持续增长过大时,会fork出一条进程来将文件重写(但是先写临时文件最后再rename),遍历新进程的内容中数据,每条记录有一条set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照类似

触发重写机制:
redis会记录上次重写时的AOF大小,默认是当AOF文件大小是上次rewrite后大小的一倍且文件大小大于64M时触发

no-appendfssync-on-rewrite 重写时是否可以运用appendfssync,默认是no即可 保证数据的安全性
auto-aof-rewrite-min-size 64M 设置重写的基准最大值
auto-aof-rewrite-percentage 100 设置重写的基准值

优势:
每秒同步 always
没修改同步 everysec
不同步 no

劣势:
相同数据集的数据而言,aof文件要远大于rbd文件,恢复速度慢于rdb
aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

3 总结

RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储

AOF持久化方式记录每次对服务器写操作,当服务器重启是会中心执行这些命令
来恢复原始数据,AOF命令以redis协议追加保存每次写的操作到文件末尾,
redis还能对aof文件进行后台重写,使得AOF文件体积不至于太大
只做缓存:如果只希望数据在服务器上运行的时候存在,可以不使用任何持久化方式。
建议:同时开启两种持久化方式

Redis事务

1 redis事务
可以一次执行多个命令,本质是一组命令的集合。
一个事务中的所有命令都会序列化,按顺序地串行化执行执行而不会被其他命令
插入,不许加塞.

2 事务能做什么
一个队列中,一次性,顺序性,排他性的执行一系列命令

3 操作
redis-server redis.conf
redis-cli -p 6379
multi开启事务
exec 提交事务
discard 放弃事务

1)正常执行
multi //开启事务
set k1 v1 //返回queued,操作入队列
set k2 v2
get k2
set k3 v3
exec //提交事务,以上数据都会有各自的相应值

2)放弃事务
multi //开启事务
set k1 v1 //返回queued,操作入队列
set k2 v2
set k3 v3
discard //撤销操作,以上操作都被撤销

3)全体连坐
multi //开启事务
set k1 v1 //返回queued,操作入队列
set k2 v2
setget k3 //错误命令setget,直接报错。导致整体失败,因为不存在这种命令
set k4 v4
exec

4)冤有头债有主
multi //开启事务
incre k1 //假设k1是aa,操作会失败。但是不会报错。但不会影响其他语句
set k2 22
set k3 33
set k4 v4
get k4
exec

5)watch监控
悲观锁/乐观锁/CAS

1)悲观锁(适合多写场景):为了防止其他操作,直接把数据锁死,其他人不可以操作。其他人只能阻塞等待,直到获取该锁时,才可以操作。传统关系型数据库的:比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

2)乐观锁(适合多读场景):当前线程不锁住当前操作的数据,其他数据可以被别人操作。如过当前线程要修改该数据,要先判断该数据是否被其他线程修改,如果被修改了,本线程放弃修改操作。可以使用版本号或者CAS算法来确定数据是否被修改。

    每条记录有个版本号,修改时,必须要保证修改时的版本号,和刚开始获取的版本号一致,才可以修改
    如果有其他人修改数据,则版本号要增加
3)CAS算法
即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数

需要读写的内存值 V
进行比较的值 A
拟写入的新值 B
当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。

CAS可以有效的提升并发的效率,但同时也会引入ABA问题。如线程1从内存X中取出A,这时候另一个线程2也从内存X中取出A,并且线程2进行了一些操作将内存X中的值变成了B,然后线程2又将内存X中的数据变成A,这时候线程1进行CAS操作发现内存X中仍然是A,然后线程1操作成功。虽然线程1的CAS操作成功,但是整个过程就是有问题的。比如链表的头在变化了两次后恢复了原值,但是不代表链表就没有变化。所以JAVA中提供了AtomicStampedReference/AtomicMarkableReference来处理会发生ABA问题的场景,主要是在对象中额外再增加一个标记来标识对象是否有过变更。

例子:
初始化信用卡可用余额和欠额

    正常模式:
        set balance 100
        set debt 0  //初始化balance是100 欠额是0

        watch balance   //监控余额
        multi
        decrby balance 20
        incrby debt 20
        exec

    加塞模式:
        watch balance   //监控余额
        //如果此时,其他进程  set balance 800
        multi
        decrby balance 20
        incrby debt 20
        exec    //会执行失败,因为在监控过程中,有其他进程修改 
    如果修改时,别人改动。自己必须先Unwatch,取消所有key的监控,重新操作。

小结:

    watch指令,类似于乐观锁,事务提交时,如果key的值已经被别人修改,则整个事务都不会执行
    通过watch命令在事务执行之前监控了多个keys,倘若在watch之后有任何key的只发生了改变,exec命令执行的事务都将被放弃,同时返回unlimulti-bulk应答以通知调用者事务执行失败

Redis主从复制和Jedis

1 Redis的复制Master/slaver
主从复制,主机数据更新后根据配置和策略,自动同步到备份机的master/slaver机制master以写为主,slaver以读为主

2 常用场景
读写分离
宕机恢复

3 操作
1)配从(库)不配主(库)

2)从库配置,salveof 主库ip 主库端口
每次和master断开后,都需要重新连接,除非配置了redis.conf文件
3)拷贝多个redis.conf文件
cp redis.conf redis6379.conf (主)
cp redis.conf redis6380.conf (从)
cp redis.conf redis6381.conf (从)

配置6379主机:
    开启daemonize yes 后台运行模式
    修改pid文件名字
    pidfile /var/run/redis6379.pid

    指定端口 :6379
    log文件名字:logfile "6379.log"

    dump.rdb名字:
    dbfilename dump6379.rdb

配置6380主机:
开启daemonize yes 后台运行模式
修改pid文件名字
pidfile /var/run/redis6380.pid

    指定端口 :6380
    log文件名字:logfile "6380.log"

    dump.rdb名字:
    dbfilename dump6380.rdb

配置6381主机:
同 6380
4)配置集群

一主二仆
    6379:
    redis-server /myredis/redis6379.conf
    redis-cli - p 6379
    info replication    //查看当前状态,都是master
    set k1 v1
    set k2 v2
    set k3 v3
    //k1 k2 k3 是在80和81称为salver之前设置
    set k4 k4
    set k6 v6   //三个redis同时set k6 v6 从机不能写输入数据
    shutdown    //主机宕机,丛机默认仍然以slaver身份待命
    redis-server /myredis/redis6379.conf //重新启动后,扔然是二者的主机

    6380:
    redis-server /myredis/redis6380.conf
    redis-cli - p 6380
    info replication
    slaveof 127.0.0.1 6379 //称为目标主机redis的 salver
    get k4  //可以获取到
    get k3  //称为salver之前,也是可以获取到的。从机称为salver时要同步主机数据
    set k6 v6
    shutdown //宕机后,如果重新启动,会以master运行。除非再次以salver身份连接

    6381:
    redis-server /myredis/redis6381.conf
    redis-cli - p 6381
    info replication
    slaveof 127.0.0.1 6379 //称为目标主机redis的 salver
    set k6 v6

薪火相传
    上一个slaver可以是下一个salver的master,savler同样可以接收
    其他salters的连接和同步请求,那么该slaver作为了链条中下一个的
    master,可以有效减轻master的写压力

    中途变更转向:会清除之前的数据,重新建立拷贝最新的
    salveof 新库id 新库port

    80设置:
        slaveof 127.0.0.1 6379

    81设置:            
        slaveof 127.0.0.1 6380

反客为主
    主机宕机后,丛机变为主机
    在丛机上输入命令:
        salveof no one //执行命令的及其成为主机
        其他丛机 salveof 命令来俯首称臣

4 复制原理
salve启动成功连接到master会发送一个sync命令
master接收到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,
在后台进程执行完毕后,master将传送整个数据文件到slave,以完成一次完全同步

全量复制:而salve服务在接收数据库文件数据后,将其存盘并加载到内存中
增量复制:master继续讲新的所有数据的修改命令一次传给salve,完成同步
但是只要是新建连接master,一次全部同步(全量复制)将被自动执行
5 哨兵模式

反客为主的自动版本,主机宕机后,丛机自动上位。

使用步骤:
1)建立sentinel.conf文件(名字一定要正确)
内容格式:
sentinel monitor 被监控主机名字(自己起名字) 127.0.0.1 6379 1 //127.0.0.1 6379 挂掉后,谁的投票大于1 才可以成为主机

  演示例子内容:
  sentinel monitor host6379 127.0.0.1 6379 1

  通过下列命令,让哨兵启动:
  redis-sentinel /myredis/sentinel.conf

  如果主机宕机,会在剩余slaver中选择一个充当主机
  在哨兵的监控下,如果之前宕机的主机重新恢复,那么
  它会变成当前master的slaver

6 复制的缺点
复制延迟
主机数据复制到丛机,如果数据量大,或者网络延迟,复制
会变得比较慢。发生延迟

Jedis

1 Jedis
Java操作redis
jar包需要:

redis.clients
jedis
3.1.0

org.apache.commons
commons-pool2
2.7.0
2 测试连通
String host = “127.0.0.1”;
Integer port = 6379;
Jedis jedis = new Jedis(host,port);
syso(jedis.ping());//打印pong

3 常用API
String host = “127.0.0.1”;
Integer port = 6379;
Jedis jedis = new Jedis(host,port);

//设置string 键值对
jedis.set(“k1”,“v1”);
jedis.set(“k2”,“v2”);
jedis.set(“k3”,“v3”);

//通过key获取值
jedis.get(“k1”);

//获取所有的keys集合
Set keys = jedis.keys("*");

//list set hash zset 都有自己的api
4 事务
普通模式:
String host = “127.0.0.1”;
Integer port = 6379;
Jedis jedis = new Jedis(host,port);

Transaction tx = jedis.multi();
tx.set("k4","v4");
tx.set("k5","v5");
tx.set("k6","v6");

//tx.discart();//回滚事务
tx.exec();//提交事务

加锁操作
String host = “127.0.0.1”;
Integer port = 6379;
Jedis jedis = new Jedis(host,port);

int balance;//可用余额
int debt;//欠额
int amtToSubtract = 10;//实刷金额

//监控balance数据,相当于加锁
jedis.watch("balance");

//让该线程休眠10秒.如果其他线程修改了balance的值,那么在watch监控下,下面的操作不会成功
Thread.sleep(10000);
balance = Integer.parseInt(jedis.get("balance"));

if(balance < amtToSubtract){
    jedic.unwatch();
    syso("余额不足");
    return false
}else{
    syso("tranction..........");
    Transaction tx = jedis.multi();
    tx.decrBy("balance",amtToSubtract);
    tx.incrBy("debt","amtToSubtract");
    tx.exec();
    balance = Integer.parseInt(jedis.get("balance"));
    debt = Integer.parseInt(jedis.get("debt"));
}

5 主从复制
主写 从读

启动6379 和 6380

Jedis jedisMaster = new Jedis(“127.0.0.1”,6379);
Jedis jedisSlaver = new Jedis(“127.0.0.1”,6380);

//80称为79的salver
jedisSlaver.salveof(“127.0.0.1”,6379);

//主机写数据
jedisMaster.set(“k1”,“v1”);

//丛机读数据
syso(jedisSlaver.get(“k1”));
6 Jedis Pool
如果需要有多个redis的实例,可以考虑使用
Jedis Pool,原理类似线程池,数据库连接池

编写JedisPoolUtil
public class JedisPoolUtil{
private static volatile JedisPool jedisPool = null;

private JedisPoolUtil{}

public static JediPool getJedisPool(){

    if(null == jedisPool){
        synchronized(JedisPool.class){
            if(null == jedisPool){
                JedisPoolConfig config = new JedisPoolConfig();
                config.setMinIdle(5);
                config.setMaxTotal(200);
                config.setMaxIdle(32);
                config.setMaxWaitMillis(100*1000);;
                config.setTestOnBorrow(true);                           jedisPool = new JedisPool(config,"127.0.0.1",6379);

            }
        }

    }
    return jedisPool;
}

public static void release(Jedis jedis){
    if(null != redis){
        //将redis对象还给redisPool
        jedis.close();
    }
}

}

//测试方法
JedisPool jedisPool = JedisPoolUtil.getJedisPool();
Jedis jedis = null;
try{
JedisPool jedisPool = JedisPoolUtil.getJedisPool();
jedis = jedisPool.getResource();//获取一个jedis连接对象
jedis.set(“k1”,“v1”);

}catch(Exception e){

}finally{
JedisPoolUtil.release(jedis);
}

springboot整合redis

1 springboot使用redis做缓存
1) pom添加依赖

org.springframework.boot
spring-boot-starter-data-redis

2) springboot开启使用缓存
@SpringBootApplication
@EnableCaching
public class DemoshiroApplication {
public static void main(String[] args) {
SpringApplication.run(DemoshiroApplication.class, args);
}
}
3) 在biz上,需要开启缓存的方法上添加注解
//在redis中,value和key 组成 key的值
@Cacheable(value = “user”, key = “#p0”)
public List findAll(){
//…
}

注意:

@CachePut(value=“users”,key="#user.id") //新增的数据,如果需要缓存支持,在其biz方法上添加该注解,将新增元素添加到缓存
@CacheEvict(value=“users”,key="#p0")//删除数据,如果该数据有缓存支持,在其biz方法上添加该注解,将删除的元素从缓存中删除

  1. 在application.properties中添加redis配置
    spring.redis.database=0
    spring.redis.host=192.168.119.100
    spring.redis.port=6379
    spring.redis.jedis.pool.max-idle=8
    spring.redis.jedis.pool.min-idle=0

2 springboot操作redis,使用RedisTemplate
@Configuration
public class RedisConfiguration {

@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
@SuppressWarnings({ “rawtypes”, “unchecked” })
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

3 springboot整合哨兵模式redis集群

1) application.properties配置文件添加哨兵配置,该模式哨兵控制提供redis读写服务,因此不需要配置redis其他属性,比如host,port等
spring.redis.sentinel.master=host6379 #哨兵主机名要和哨兵配置文件中一致
spring.redis.sentinel.nodes=192.168.119.100:26379
spring.redis.jedis.timeout=6000
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
2) 修改哨兵配置文件(在配置主从redis服务器时(slaveof),使用其ip地址,不要使用127.0.0.1)
port 26379
dir “/soft/redisConf”
maxclients 4064
protected-mode no
sentinel deny-scripts-reconfig yes
sentinel monitor host6379 192.168.119.100 6379 1
sentinel config-epoch host6379 2
sentinel leader-epoch host6379 2
sentinel known-replica host6379 192.168.119.100 6380
sentinel known-replica host6379 192.168.119.100 6381
sentinel current-epoch 2

4 Redis Cluster

哨兵模式缺陷:
在哨兵模式中,仍然只有一个Master节点。当并发写请求较大时,哨兵模式并不能缓解写压力。我们知道只有主节点才具有写能力,那如果在一个集群中,能够配置多个主节点,是不是就可以缓解写压力了呢?答案:是的。这个就是redis-cluster集群模式。

Redis-cluster集群概念
(1)由多个Redis服务器组成的分布式网络服务集群;
(2)集群之中有多个Master主节点,每一个主节点都可读可写;
(3)节点之间会互相通信,两两相连;
(4)Redis集群无中心节点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值