写在前面:
之前投递各大公司,在招聘条件中redis是出现频率很高的一门技术。在学校只学习了Oracle,redis在平常开发中听到的很多用到的也很多,但没有深入进行学习过。趁着项目间隙赶快把redis来系统学一遍。还是老样子,B站找个视频教程,跟着老师做,多做笔记,多思考,熏着熏着就上头了。哈哈哈哈。
奉上视频教程地址:
https://www.bilibili.com/video/av68608598from=search&seid=3858464212406452310
百度网盘课程学习资料:
链接:https://pan.baidu.com/s/1zh2BIfOqG7uK0-0Ocj5_3Q
提取码:57tb
学习记录
NoSQL
NoSQL =Not Only SQL意即“不仅仅是SQL”, 泛指非关系型的数据库。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
NoSQL数据模型
KV键值(Redis) BSON键值(MongoDB) 列族(HBase) 图形(Neo4J, InfoGrid)
ACID原理 VS 分布式数据库CAP原理
ACID(原子性、一致性、独立性、持久性)
CAP(强一致性、高可用性、分区容错性)
CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。
CA:可扩展性略差CP:性能方面略差 AP:数据一致性方面略差
BASE
为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。
BA:基本可用 S:软状态 E:最终一致
分布式 VS 集群
分布式:不同的多台服务器上部署不同的服务模块,它们之间通过RPC之间通信和调用,对外提供服务和组内协作。
集群:不同的多台服务器上部署相同的服务模块,通过分布式调度软件进行统一的调度,对外提供服务和访问。
Redis简介
RemoteDitionary Server远程字典服务器, 是一个高性能的(key/value)分布式内存数据库,基于内存运行 并支持持久化的NoSQL数据库。同时支持多种数据类型,支持数据的备份。
Redis安装
l /opt目录下,解压命令:tar -zxvf redis-3.0.4.tar.gz
l 在redis-3.0.4目录下执行make命令
l 报错,缺少gcc
l Yun install gcc
l 安装完gcc还报错,make distclean
l 再执行make即可
l 查看默认安装目录:usr/local/bin(相当于windows的programfile目录)
l 复制/opt/redis-3.0.4目录下的redis.conf配置文件到/myredis下作为备份
l 修改redis.conf文件将里面的daemonize no 改成 yes(37行),让服务在后台启动
l Redis-server /myredis/redis_aof.conf
l Redis-cli –p 6379
默认16个数据库,类似数组下标从零开始,初始默认使用零号库。
Select *切换数据库
Dbsize 查看key的数量
Keys * 列出所有的key
Flushdb 清空当前库的key
FlushAll 情况所有库的key
字符串String
set get append strlen del
incr /decr 增减1
incrbykey value | decrby key value
getrangekey 起 止(0 -1)
setrangekey 起 值
setex 键时间 值 ttl 键 查看剩余过期时间
setnx 键值 如果键不存在才创建
mset 【键1 值1。。。】
mget 【键1 键2。。。】
msetnx 【键1 值1。。。】如果其中某个键已经存在,则后面的键都不创建
列表List 单键多值 可重复
Lpush 键【值。。。】 Rpush 键 【值。。。】 Lrange 键 0 -1
Lpop 键 Rpop键
Lindex 键下标
Llen 键
Lrem 键个数 值 删n个
Ltrim 键起 止 截取
RpopLpush源列表 目标列表 移除最右边的键到目标列表最左边
Lset 键下标 值
Linsert 键 after/before 当前值 新值
集合Set 单键多值 不可重复
Sadd 键【值。。。】 Smembers 键 Sismember 键 值
Scard 键集合元素个数
Srem 键值 删除集合中的元素
Srandmember键 个数 集合中随机出几个
Spop 键随机出栈
Smove 键1 键2 键1中某个值 移动元素到另一个集合
Sdiff 键1 键2 交集
Sinter 键1 键2差集
Sunion 键1 键2并集
哈希Hash kv模式不变 但v是一个键值对
Hset 键属性 值
Hget 键属性
Hmset 键【属性1 值1。。。】
Hmget 键【属性1。。。】
Hdel 键属性
Hlen 键
Hexists 键属性1
Hkyes 键
Hvals 键
Hincr[ByFloat]键 属性 【值】
有序集合Zset 在set基础上加了一个score值
Zadd 键【score 值1。。。】
Zrange 键 0 -1 【withscores】
Zrem 键值 删除某个值
Zcard 键集合个数
Zrank 键值 根据值获得下标
Zscore 键值 根据值获得分数
Zcount 键开始分数 结束分数 统计分数范围内的个数
Redis.conf配置文件
Units单位
Includes包含
General通用
SNAPSHOTTING快照RDB文件
REPLICATION复制
Security安全
Config get dir | requirepass
Auth 密码
Limits限制
----清除淘汰策略
最近最少用
Random随机
Ttl有限时间内
Noevication永不清理
AppendOnly File AOF文件
持久化之RDB dump.rdb
##############SNAPSHOTTING##########
★在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。
★将备份文件 (dump.rdb)移动到 redis 安装目录并启动服务即可。
★CONFIG GET dir获取目录。(获取dump.rdb文件所在目录)
★Save <Seconds> change配置策略。
1分钟内改1W次
5分钟内改10次
15分钟内改1次
★当shutdown时,会产生最新的dump.rdb文件。如果flushdb了,那么dump.rdb都为空了。Ps:保存完后 把dump.rdb文件 备份一个 dump_bak.rdb文件。
主动 save保存 VS bgsave。Save只管保存 其他不管 全部阻塞。
★Redis-check-rdb –fix dump.rdb 修复损坏的rdb文件
★优缺点:适合大规模数据且完整性要求不高的。意外down可能会丢失最后一次的内容。
★动态所有停止RDB保存规则的方法:redis-cli config set save""
持久化之AOF appendonly.aof
#######APPEND ONLY MODE##############
★以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
★启动:修改默认的appendonly no,改为yes(504行)
Ps: aof和rdb可共存 498行
★恢复:重启redis然后重新加载
★修复:redis-check-aof–fix appendonly.aof解决并修复损坏的文件
★优先加载.aof文件
★Appendfsync
每修改同步always同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
每秒同步everysec 异步操作,每秒记录 如果一秒内宕机,有数据丢失
不同步 no
★缺点
相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同
★ 若aof文件变大,可以在后台对aof瘦身。
★AOF有序保存了执行的写操作
Redis—事务 (redis部分支持事务)
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。
---->Multi开启事务
---->exec执行事务/discard放弃事务
全体连坐:(一人错误全体受罚)前后都不执行 直接抛错误(redis部分支持事务)
冤头债主:(谁错谁没有)数据类型不一致 编译不报错 运行时报错(redis部分支持事务)不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。
悲观锁----强调数据一致性
每次去拿数据时,认为别人已经或者会去修改数据,所以每次拿数据时,都会上锁,这样别人想去拿数据时,就会堵塞,除非它拿到了锁。
传统关系型数据库里用了这些锁机制,比如行锁、表锁、读写锁、都是在操作之前先上锁。
乐观锁
每次拿数据时都认为别人不会修改,所以,不上锁。但在更新时会判断一下,在此期间内别人是否更新了这个数据。可以使用版本号机制。
策略:提交的版本 必须 大于记录当前的版本才能执行。
Watch [key。。。]
监视一个或多个key,如果事务在执行这些key之前,被其他人/命令 改动,那么 你的整个事务队列都不被执行,会被打断。
Watch≈乐观锁
★Watch在事务之前执行/监视 key
★事务提交时(exec)如果key的值被别人改动了,那么整个事务队列都不会被执行
★通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化, EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败
Unwatch :取消所有监控key的监视
Redis的发布订阅
进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis主从复制(Master/Slave)
★读写分离&容灾恢复:
行话:也就是我们所说的主从复制,主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。
★大头
配从(库)不配主(库)
从库配置:Slaveof 主库ip 主库端口
每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件
info replication (查看角色)
修改配置文件细节操作
拷贝多个redis.conf文件
开启daemonize yes
pid文件名字
指定端口
log文件名字
dump.rdb名字
★一主二仆一个Master两个Slave
主机死了从机原地等位 一切照旧
从机死了回来成主机 要想跟上大部队 重新slaveof 每次断开主机,都要slaveof除非写进配置文件
只有主机允许写
★薪火相传
上一个Slave可以是下一个slave的Master,Slave同样可以接收其他 slaves的连接和同步请求,那么该slave作为了链条中下一个的master, 可以有效减轻master的写压力
★反客为主 SLAVEOFno one
使当前数据库停止与其他数据库的同步,转成主数据库
★复制原理
全量复制
当第一次slave连接master时,会发送一个sync同步命令给master,master收到命令将整个数据文件传送到slave完成第一次同步
增量复制
已经连接上了,master继续将收集到的命令传给slave,完成同步。缺点:复制会有延时…..
Ps:只要是重新连接到master,就一次完成同步(属于全量复制)将被自动执行….
★哨兵模式
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
调整结构,6379带着80、81
自定义的/myredis目录下新建sentinel.conf文件,名字绝不能错
配置哨兵,填写sentinel.conf文件内容
sentinel monitor 被监控数据库名字(自己起名字) 127.0.0.1 6379 1
上面最后一个数字1,表示”主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机”(数字1代表 进行的是这样的方法来操作)
启动哨兵
redis-sentinel /myredis/sentinel.conf
79为被监控的主机
79挂了 81成了master 80自动跟81为大哥
20.Redis主从复制(Master/Slave)
★Jedis所需要的jar包
commons-pool-1.6.jar jedis-2.1.0.jar
★JedisPoolUtils
public class JedisPoolUtils { private static volatile JedisPool jedisPool = null; private JedisPoolUtils(){} public static JedisPool getJedisPoolInstance(){ if(null == jedisPool){ synchronized (JedisPoolUtils.class){ if(null == jedisPool){ JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(100); jedisPoolConfig.setMaxWaitMillis(100*100); jedisPoolConfig.setTestOnBorrow(true); jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1",6379); } } } return jedisPool; } public static void release(JedisPool jedisPool, Jedis jedis){ if(null != jedis){ jedisPool.returnResourceObject(jedis); } } }
★TestJedisPoolUtils
public class TestJedisPoolUtils { public static void main(String[] args) { JedisPool jedisPool = JedisPoolUtils.getJedisPoolInstance(); Jedis jedis = null; try { jedis = jedisPool.getResource(); jedis.set("k1","v1"); }catch (Exception e){ e.printStackTrace(); }finally { JedisPoolUtils.release(jedisPool,jedis); } } }