Nosql
串行–
1.1.1. NoSQL****适用场景
l 对数据高并发的读写
l 海量数据的读写
l 对数据高可扩展性的
1.1.2. NoSQL****不适用场景
l 需要事务支持
l 基于sql的结构化查询存储,处理复杂的关系,需要即席查询。
l (用不着sql的和用了sql也不行的情况,请考虑用NoSql****)
Redis
1.1.1. 多样的数据结构存储持久化数据
1.1.1. Redis****介绍相关知识
端口6379从何而来 Alessia Merz | 默认16个数据库,类似数组下标从0开始,初始默认使用0号库 使用命令 select |
---|---|
9宫格键 | flushall通杀全部库 |
flushdb清空当前库 | |
统一密码管理,所有库同样密码。 |
Redis是单线程+多路IO复用技术
特点:
- 数据类型丰富
- 支持持久化存储
- 支持主从
- 支持分片
CAP的3进2
数据结构
查找常用API http://www.redis.cn/commands.html
KEY
- keys *查看当前库所有key (匹配:keys *1)
- exists key判断某个key是否存在
- type key 查看你的key是什么类型
- del key 删除指定的key数据
- unlink key 根据value选择非阻塞删除
- 仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。
- expire key 10 10秒钟:为给定的key设置过期时间
- ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
String
setex
设置键值的同时,设置过期时间,单位秒。
set
get
append
strlen
setnx
mset
同时设置一个或多个 key-value对
mget
同时获取一个或多个 value
msetnx
同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
List
List的数据结构为快速链表quickList
Set
Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所有添加,删除,查找的*复杂度都是***O(1)**。
Hash
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
类似Java里面的Map<String,Object>
数据区域化
Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。
Zset(sorted set)
不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。
zadd
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
zrange
返回有序集 key 中,下标在
带WITHSCORES,可以让分数一起和值返回到结果集。
zrangebyscore key minmax [withscores] [limit offset count]
返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
zrevrangebyscore key max min [withscores] [limit offset count]
同上,改为从大到小排列。
- 如何利用zset实现一个文章访问量的排行榜?
zset底层使用了两个数据结构
(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。
(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。
新数据类型
Bitmaps
计算出任意一天都访问过网站的用户数量(例如月活跃就是类似这种) , 可以使用or求并集
HyperLogLog
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
快速计算基数并返回
比如每月活跃用户可以使用每天的活跃用户来合并计算
Geospatial
geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing
配置文件参数
自定义目录:/myredis/redis.conf
###INCLUDES**包含###**
bind
默认情况bind=127.0.0.1只能接受本机的访问请求
不写的情况下,无限制接受任何ip地址的访问
- **protected-**mode
将本机访问保护模式设置no
- Port
端口号,默认 6379
tcp-backlog
Redis****的发布和订阅
1.1. 什么是发布和订阅
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
Redis 客户端可以订阅任意数量的频道
1. **Redis_Jedis_**实例
1.1. 完成一个手机验证码功能
要求:
1、输入手机号,点击发送后随机生成6位数字码,2分钟有效
2、输入验证码,点击验证,返回成功或失败
3、每个手机号每天只能输入3次
1. **Redis_**事务 锁机制 秒杀
事务:
eg:有很多人有你的账户,同时去参加双十一抢购;
Multi:先组队 ,
- 组队出错,则都不能提交;
Exec:执行阶段
- 一个出错,其他的照常运行,不会回滚;
组队的过程中可以通过discard来放弃组队。
锁
悲观锁
无论什么情况,操作之前先上锁;
乐观锁
都可以同时操作,但是更新的时候比较版本
乐观锁适用于多读的应用类型,这样可以提高吞吐量
Redis就是利用这种check-and-set机制实现事务的。
事务三大特性
- 单独的隔离操作
- 没有隔离级别的概念
- 不保证原子性
秒杀案例
使用ab增加模拟并发
连接超时问题使用连接池解决;
超卖现象
- 使用乐观锁解决,但是又有库存遗留问题;
库存遗留
使用LUA脚本
利用lua脚本淘汰用户,解决超卖和遗留问题。
redis 2.6版本以后,通过lua脚本解决争抢问题,实际上是redis 利用其单线程的特性,用任务队列的方式解决多任务并发问题。 意思就是进行了排队
Redis持久化之RDB
Redis 提供了2个不同形式的持久化方式。
RDB(Redis DataBase)
- 在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里
- Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失**。
- bgsave:Redis会在后台异步进行快照操作,** 快照同时还可以响应客户端请求。
AOF(Append Of File)
以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
AOF****默认不开启
可以在redis.conf中配置文件名称,默认为 appendonly.aof
AOF文件的保存路径,同RDB的路径一致。
文件过大会进行Rewrite
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。
主从复制
主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主,Slave****以读为主
读写分离性能扩展
- slave-priority 10 设置从机的优先级,值越小,优先级越高,用于选举主机时使用。默认100
- slaveof
成为某个实例的从服务器 - 可以将配置增加到文件中。永久生效。
1.1.1. 一主二仆
1.1.1. 薪火相传**
1.1.1.** 反客为主
1.1. 哨兵模式(sentinel)
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
sentinel monitor mymaster 127.0.0.1 6379 1
其中mymaster为监控对象起的服务器名称, 1 为至少有多少个哨兵同意迁移的数量。
1.1.1. 故障恢复
Redis集群
容量不够,redis如何进行扩容?
并发写操作, redis如何分摊?
Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
普通方式登录
可能直接进入读主机,存储数据时,会出现MOVED重定向操作。所以,应该以集群方式登录。
-c 采用集群策略连接,
设置数据会自动切换到相应的写主机
分配原则尽量保证每个主数据库运行在不同的IP地址,每个从库和主库不在一个IP地址上。
Redis应用问题解决
1.1. 缓存穿透
key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。,可能是被攻击了
1.1. 缓存击穿
key对应的数据存在,但在redis中过期,大量并发导致的
1.1. 缓存雪崩
很多key过期
1.1. 分布式锁
需要一种跨JVM的互斥机制来控制共享资源的访问
set sku:1:info “OK” NX PX 10000
NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
有个问题,set过程出错,导致锁没法被释放
优化之设置锁的自动施放时间
但是有个问题,因为有可能A没有执行完。锁被释放了。释放了别人的锁;
setnx获取锁时,设置一个指定的唯一值(例如:uuid);释放前获取这个值,判断是否自己的锁
删除操作缺乏原子性;判断完uuid 锁过期
优化之UUID防误删,
为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
- 互斥性。在任意时刻,只有一个客户端能持有锁。
- 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
- 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
- 加锁和解锁必须具有原子性。
Redis6.0****新功能
持续关注ing
Others:
原子性
所谓原子操作是指不会被线程调度机制打断的操作;
这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。
(1)在单线程中, 能够在单条指令中完成的操作都可以认为是”原子操作”,因为中断只能发生于指令之间。
(2)在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。
Redis单命令的原子性主要得益于Redis的单线程。
Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。
- Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。
求集合中不重复元素个数的问题称为基数问题。