NoSQL = Not Only SQL.
高并发读写 会导致关系型数据库压力过大
NOSQL分类
NOSQL优点:数据之间无关系, 易拓展, 灵活的数据模型, 大数据量,高性能, 高可用。
redis: 高性能键值对数据库
支持的数据结构 redis应用场景 jedis连接步骤
Jedis配置
- 写JedisConfig 配置连接数 账号密码 连接时间 地址 等等
- 写service 要进行哪些操作(其中需要的一些获得jedis的对象配置在@configuration中 比如jedispool什么的)
- 封装Prefix(prefix, expires) 使得 key不冲突,按模块区分
字符串常用操作:
- 当做整形用: incr 、 incrby、del...
- 当做字符串: set、 append…
哈希表常用操作:
- hset 表名 key value(存值) hmset 表名 key1 value1 key2 value2...(多)
- hget 表名 key(取值) hmget 表名 key1 key2...(多)
- del 表名(删除整个集合) hdel 表名 key删除这个key value
- hincrby 表名 key number(要增加的值) 给key里的value+number
列表常用操作:
- lpush/rpush 表名 value1,value2,value3...
- lrange 表名 from to ->[from, to]里的元素 从0开始并且包括尾索引
- lpop/rpop 表名
- llen 表名
-
常用于消息队列, 多个程序之间的通信。 生产者:一个程序往list中添加元素。 消费者:一个程序往list中取走元素。为防止消费者取走后没有正常消费(出现了一些异常等等), 通常需要使用poppush操作,在取走的同时放进一个备份队列,当确定无误后,再将备份队列中的数据删除。
消息通信
集合(set) 常用命令:
- sadd 表名 value1, value2 ...
- srem 表名 value1, value2 ...
- smembers 表名(获得全集)
- sismember 表名 value(判断value在不在s中)
- 集合运算 union、diff、inter...
- scard 表名 (获得该表的长度)
有序集合(sorted-set)常用命令:
实质上是一个类似TreeMap的东西,等价于TreeMap(value,score)且按score排序
- zadd 表名 score1 value1 score2 value2 score3 value3
- zscore 表名 value(获得该value的分数 )
- zcard 表名(获得该表的长度)
redis的特性
多数据库, 类似MYSQL的不同数据库, REDIS有0-15(共16个数据库),通过SELECT切换。
支持事务, multi exec discard.
redis持久化
RDB:每过一段时间将数据写入硬盘
AOF:一般用来记录日志,修改后就同步
无持久化
- 单节点redis和redis cluster不同点:
- jediscluster不支持ping操作
- jediscluster不能同时操作多个key(mset、mget)
- jediscluster不支持flushall、flushdb操作
单线程的Redis为什么这么快?
- 纯内存操作
- 单线程操作, 避免了频繁的上下文切换
- 采用了非阻塞I/O多路复用机制
- 传统并发模型: 每个I/O流都有一个新的线程管理
- I/O多路复用: 单个线程, 通过跟踪每个I/O流的状态,管理多个I/O流
REDIS的过期策略以及内存淘汰机制:定期删除+惰性删除策略
- 定时删除(消耗资源大,到时间就一定要删除,可能此时正有请求),定期随机检查部分KEY并进行删除
- 定期删除如果没有删除到,就会执行惰性删除(在获取某个Key的时候,Redis会检查这个Key是否设置了过期时间,如果过期了,此时就会删除)
- 如果即没定期淘汰,也没访问,那么会导致内存越来越高。就应该采用内存淘汰机制(ALLKEYS-LRU 键空间中,移除最近最少使用的KEY)。
四个常见问题:
-
缓存和数据库双写一致性问题
- ...
-
缓存雪崩问题
- 原因:缓存同一时间大面积失效,请求又都怼到了数据库上。
- 解决方案:给缓存失效时间加个随机值, 互斥锁, 双缓存(?)
-
缓存击穿问题
- 原因:所有请求避开缓存,导致所有请求怼数据库
- 解决:利用互斥锁(获得锁才能请求数据库), 异步更新机制(维护一个缓存失效时间,如果缓存过期了,异步起一个线程去读数据库,更新缓存),提供一个能迅速判断请求是否有效的拦截机制(?如果Key不合法,直接返回)
-
缓存的并发竞争问题
- 多个子系统Set 一个Key(如果不要求按顺序对Key操作, 使用分布式锁, 抢到锁就可以set)、(要求顺序,可以在VALUE上加上时间戳, 根据时间戳来进行时间操作)。
-
一些常见操作
- setnx(SET if Not eXist)
- setex(set and expire) 设置值并且将key的生存时间设为seconds。
- hdel(删除哈希表中的一个或多个指定域,不存在的域将被忽略) HDEL KEY field[field ...]
- hmset (hash multi set)
- hscan(hash iterator) hscan(key, cursor, match), cursor用于指定游标, match用于过滤结果。【cursor从0开始, 当cursor为0时结束。】
- zrem(删除多个)。
-
jediscluster使用crc16哈希槽算法
-
分布式session
- 考虑到使用集群来跑项目 , session难以共享。
- 使用redis模拟session。 cookie保存一个token, 然后通过这个token来确定一个用户在redis中的数据。(其中涉及到json序列化和反序列化)
-
jediscluster API 基本与 cmd client一致, 用个service或者util简单封装一下就好。
-
jedis和redistemplate:http://shift-alt-ctrl.iteye.com/blog/1886831
-
spring redistemplate
- 内部操作的是jedis
- redisTemplate.opsForValue();//操作字符串
- redisTemplate.opsForHash();//操作hash
- redisTemplate.opsForList();//操作list
- redisTemplate.opsForSet();//操作set
- redisTemplate.opsForZSet();//操作有序set
- 通过4个序列化方法定义序列化方式(貌似不使用默认也不指定,是通过byte传输), 其它使用参考API。
-
redis分布式锁:
- 竞争资源抢占一个锁(一个String表示某个特定资源), 锁的有效时间(锁持续的时间),超时时间(获取锁失败后重试的时间)
- 加锁逻辑
- setnx, 如果成功则成功,否则
- get 判断锁是否超时, 超时的情况下 getset并且判断getset得到的值是否和之前一致(CAS的思想),如果是的话返回true,否则
- 不断尝试获得锁
- 解锁逻辑
- 如果当前时间 > 锁的到期时间 , 不做处理
- 否则删除key
-
redis pipeline:
- redis 是一个基于TCP 的C/S 架构软件, 当客户端向服务端发送请求时, 需要消耗一定的时间用于往返传输数据。如果客户端需要服务端进行100次操作, 显然逐条发送会造成redis 空闲(处理速度大于操作到来的速度) 而 资源浪费。
- 第一种方式是通过batch, 单条批量操作, multiset、multiget这样。
- 第二种方式是通过pipeline, 思路一样, 只不过用在set上, 没法multi多个set,而pipeline是把指令作为流水线打过去。
-
redis lua:
- 通过脚本实现CAS,防止出现并发问题(相当于全局串行了)
网友评论