Redis基础知识
端口:6379
默认16个数据库,下标从0开始
单线程:redis是单线程+io多路复用而Memchached:多线程+锁
redis数据类型:String set list hash zset
- string——适合最简单的k-v存储,类似于memcached的存储结构,短信验证码,配置信息等,就用这种类型来存储。
- hash——一般key为ID或者唯一标示,value对应的就是详情了。如商品详情,个人信息详情,新闻详情等。
- list——因为list是有序的,比较适合存储一些有序且数据相对固定的数据。如省市区表、字典表等。因为list是有序的,适合根据写入的时间来排序,如:最新的***,消息队列等。
- set——可以简单的理解为ID-List的模式,如微博中一个人有哪些好友,set最牛的地方在于,可以对两个set提供交集、并集、差集操作。例如:查找两个人共同的好友等。
- Sorted Set——是set的增强版本,增加了一个score参数,自动会根据score的值进行排序。比较适合类似于top 10等不根据插入的时间来排序的数据。
Redis的特点:
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
Redis的优势:
- 读写性能优异,性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 操作都是原子的 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
- 丰富的特性 – Redis还支持发布订阅, 通知, key 过期等等特性。
- 可以持久化,支持AOF和RDB
Redis与其他key-value存储有什么不同?
- Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
- Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
key操作
| 方法 | 作用 |
|---|---|
| keys * | 查看当前库所有的键 |
| exists <key> | 判断是否存在key |
| del <key> | 删除某个键 |
| expire <key> <second> | 设置键过期时间 单位是s秒 |
| ttl <key> | 查看还有多少秒过期 -1表示用不过期 -2表示已经过期 |
| move <key> <db> | 把键移到另一个库下 |
| dbsize | 查看数据库key的数量 |
| flushdb | 清空当前库 |
| flushall | 通杀所有库 |
- String:String是二进制安全的,可以包含任何数据源,最大512m
| 方法 | 作用 |
|---|---|
| get <key> | 查看对应的键值 |
| set <key> <value> | 添加键值对 |
| append <key> <value> | 将给定的value 追加到原值的末尾 |
| strlen < key > | 获取值得长度 |
| setnx <key> <value> | 当key 不存在的时候设置key值 |
| incr <key> | 将key中储存的数字加1,如果为空,则值为1 |
| decr <key> | 将key中储存的数字减1,如果为空,则值为-1 |
| incrby/decrby | <key> <步长> 将key中的数字增减 |
String批量处理
| 方法 | 作用 |
|---|---|
| mset <key1> <value1> <key2> <value2> | 同时设置多个键值对 |
| mget <key1> <key 2> | 同时获得多个值 |
| msetnx <key1> <value1> <key2> <value2> | 当给定的key都不存在 |
| getrange <key> <start> <stop> | 类似sunstring |
| setrange <key> <start> <stop> | 类似sunstring覆盖原始值 |
| setex <key> <过期时间> <value> | 设置键值的同时,给定过期时间 |
| getset <key> <value> | 以旧换新,设置了新的值同时得到旧值 |
2.List:链表
单键多值
Redis列表是简单的字符串列表,从左或者从右插入
底层是双向链表,对两端的操作性能很高,通过下标查询性能很低
| 方法 | 作用 |
|---|---|
| lpush/rpush <key> <value1> <value2> .. | 从左或从右插入多个值 |
| lpop/rpop <key> | 从左边或右边吐出一个值,值光键亡 |
| rpoplpush <key1> <key2> | 从key1 右边吐出一个值到key2的左边 |
| lrange <key> <index> | 按照索引下标获取元素 从左到右 |
| lindex <key> <index> | 按照索引下标获取元素 从左到右 |
| llen <key> | 获取列表长度 获取列表长度 |
| linsert <key> before <value> <newvalue> | 在key中value前插入newvalue |
3.hash:键值对集合,类似map<String,Object>
| 方法 | 作用 |
|---|---|
| hset <key> <filed> <value> | 给key 集合中的file 键赋值value |
| hget <key1> <field> | 从key1 集合file取出value |
| hmset <key1> <field1> <value1> <field2> <value2> | 批量设置hash的值 |
| hexists <key> <field> | 查看key中的field 是否存在 |
| hkeys <key> | 列出key中所有的filed |
| hvals <key> | 列出该hash集合中所有的value |
4.Set:类似list的无序集合,保证列表中不会有重复数据,底层是一个value为null的hash表
| 方法 | 作用 |
|---|---|
| sadd <key> <value1> <value2> | 将多个元素加入到key中,重复值忽略 |
| smembers <key> | 取出该集合的所有值 |
| sismember <key> <value> | 判断集合key中是否有该value值 有就1 没有0 |
| scard <key> | 返回该集合的元素个数 |
| srem <key> <value1> <value2> | 删除集合中的某个元素 |
| spop <key> | 随机吐出该集合一个值 |
| srandmember <key> <n> | 随机从集合中取出n个值,不会从集合中删除 |
| smove <key1> <key2> <value> | 将key1中的value 移动到key2 中 |
| sinter <key1> <key2> | 返回两个集合的交集元素 |
| sunion <key1> <key2> | 返回两个集合的并集 |
5.zset:与set集合非常相似,每个成员都关联了score,可以用来排序
| 方法 | 作用 |
|---|---|
| zadd<key><score1><value1><score2><value2> | 将一个或多个元素以及score加入zset |
| zrange<key><start><stop> withscore | 返回下标在区间内的集合,带有score |
| zrangebyscore <ket> <min> <max>[withscore] [limit offset count] | 返回key中 score介于min和max中的成员,升序排列 |
| zrevrangerbyscore <key> <min> <max> [withscore] [limit offset count] | 降序 |
| zincrby <key> <increment> <value> | 在key集合中的value上增加increment |
| zrem <key> <value> | 删除key集合下的指定元素 |
| zcount <key> <min><max> | 统计 区间内的元素个数 |
| zcord <key> | 获取集合中的元素个数 |
| zrank <key><value> | 查询value在key中的排名,从0开始 |
Redis事务
https://www.cnblogs.com/DeepInThought/p/10720132.html
https://blog.csdn.net/Future_LL/article/details/86675620
Redis事务的概念:
Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
Redis事务没有隔离级别的概念:
批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。
Redis不保证原子性:
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
1.悲观锁:悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,当其他线程想要访问数据时,都需要阻塞挂起。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁,读锁,写锁等,都是在操作之前先上锁。
在Java中,synchronized的思想也是悲观锁。
2.乐观锁:每次拿数据的时候总认为别人不会修改数据,所以不会上锁。但是更新的时候回去判断别人有没有更改数据,使用版本号机制。乐观锁适用于多读的应用类
型,可以提高吞吐量。一般会使用版本号机制或CAS操作实现:
-
version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
-
CAS(Check And Set【先检查再动手设置】)
CAS操作方式:即 compare and set,CAS是乐观锁技术,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。
3.Redis使用乐观锁:redis就是利用check-and-set机制实现事务
4.三大特性:
- 单独的隔离操作:事务中的所有命令都会序列化,按顺序执行。不会被其他客户端打断
- 没有隔离级别概念:队列中的命令没有提交之前不会被执行,事务外不能查看事务内的更新
- 不能保证原子性:跳过错误,依旧执行,没有回滚
分布式
什么是分布式锁
在学习Java多线程编程的时候,锁是一个很重要也很基础的概念,锁可以看成是多线程情况下访问共享资源的一种线程同步机制。这是对于单进程应用而言的,即所有线程都在同一个JVM进程里的时候,使用Java语言提供的锁机制可以起到对共享资源进行同步的作用。如果分布式环境下多个不同线程需要对共享资源进行同步,那么用Java的锁机制就无法实现了,这个时候就必须借助分布式锁来解决分布式环境下共享资源的同步问题。分布式锁有很多种解决方案,今天我们要讲的是怎么使用缓存数据库Redis来实现分布式锁。
第一种:使用redis的watch命令进行实现
第二种:使用redis的setnx命令进行实现还有这个https://www.cnblogs.com/linjiqin/p/8003838.html
[redis实现秒杀实例](https://www.cnblogs.com/jasonZh/p/9522772.html)
redis持久化:
两种方式:rdb(redis database)和aof(append of file)
1.RDB:在指定时间间隔内,将内存中的数据作为一个快照文件(snapshot)写入到磁盘,读取的时候也是直接读取snapshot文件到内存中
①持久化过程:redis单独创建(fork)一个进程来持久化,会先将数据写入临时文件中,待上次持久化结束后,会将该临时文件替换上次持久化文件,比aof高效,但是最后一次数据可能会丢失
②Fork:在linux中,fork()会产生一个跟主进程一样的子进程,出于效率考虑,主进程和子进程会公用一段物理内存,当发生改变的时候,才会把主进程“”写时复制”一份给子进程
③Redis备份的文件:在redis.conf中设置,dbfilename默认为:dump.rdb
④ Rdb保存策略:
- 900s 1 file change
- 300s 10file change
- 60s 10000file change
⑤Rdb的备份:
- config get dir 得到备份的文件夹
- 复制备份文件
⑥Rdb恢复:
- 关闭redis
- 将备份文件复制到工作目录下
- 启动redis,自动加载
2.AOF : 以日志形式记录每个写操作,启动时通过日志恢复操作
- 开启AOF:默认不开启,进入redis.conf找到appendonly yes打开
- 修复AOF:redis-check-aof –fix appendonly.aof
- 同步频率:每秒记录一次,如果宕机该秒记可能失效
- Rewrite:bgrewriteaof 因为日志是追加方式,文件会越来越大,当超过了设置的阈值时,日志文件会压缩,保留仅可以恢复的日志
3.RDB和AOF对比
RDB优点:
- 节省磁盘空间
- 恢复速度快
ROD缺点:
- 数据太大时,比较消耗性能
- 一段时间保存一次快照,宕机时最后一次可能没有保存
AOF优点:
- 备份机制更加稳健
- 可读的日志文件,通过aof恢复更加稳健,可以处理失误
AOF缺点:
- 比RDB更占磁盘
- 备份速度较慢
- 每次都同步日志,有性能压力
RDB和AOF哪个好
官方推荐都启用
对数据不敏感,单独用RDB
不建议单独使用AOF
若作为纯缓存使用,可以都不开启
高可用
1.Redis主从复制:
是什么:主从复制就是主机数据更新后根据配置和策略,自动同步到备份机的master/slaver机制,master写为主,slave读为主
用处:
- 读写分离,性能拓展。
- 容灾快速恢复
配置服务器(配从不配主):
- 拷贝多个redis.conf文件
- 开启daemonize yes
- Pid文件名字
- 指定端口
- Log文件名字
- Dump.rdb名字
- Appendonly 关掉或者换名字
2.集群:
实现对redis的水平拓展,启动n的redis节点,将整个数据分布在这n个节点中
1.配置conf文件:
- 拷贝多个redis.conf文件
- 开启daemonize yes
- Pid文件名字
- 指定端口
- Log文件名字
- Dump.rdb名字
- Appendonly 关掉或者换名字
2.配置cluster文件:
- cluster-enable yes 打开集群模式
- cluster-config-file xxx.conf 设置生成的节点配置文件名
- cluster-node-timeout 15000设置节点失联时间,超多该时间(毫秒),集群自动进入主从切换
Redis作用
1.作为数据库
2.作为缓存
3.作为消息中间件
Redis应用场景
粗解1:
redis是一个key-value存储系统,可以用在如下场景,1,2,5用得较多
1、缓存
热点数据(经常会被查询,但是不经常被修改或者删除的数据),首选是使用redis缓存。
2、计数器
单线程避免并发问题,高性能,如减库存。
3、队列
相当于消息系统,ActiveMQ,RocketMQ等工具类似,但是个人觉得简单用一下还行,如果对于数据一致性要求高的话还是用RocketMQ等专业系统。
4、位操作
使用setbit、getbit、bitcount命令,如统计用户签到,去重登录次数统计,某用户是否在线状态等;
redis内构建一个足够长的数组,每个数组元素只能是0和1两个值,然后这个数组的下标index用来表示我们上面例子里面的用户id(必须是数字哈),那么很显然,这个几亿长的大数组就能通过下标和元素值(0和1)来构建一个记忆系统,上面我说的几个场景也就能够实现。用到的命令是:setbit、getbit、bitcount
5、分布式锁与单线程
验证前端的重复请求(可以自由扩展类似情况),可以通过redis进行过滤:每次请求将request Ip、参数、接口等hash作为key存储redis(幂等性请求),设置多长时间有效期,然后下次请求过来的时候先在redis中检索有没有这个key,进而验证是不是一定时间内过来的重复提交。
秒杀系统,基于redis是单线程特征,防止出现数据库“爆破”
6、最新列表
redis的 LPUSH命令构建List。
7、排行榜
谁得分高谁排名往上。命令:ZADD(有序集,sorted set)。
粗解2:
下面列出11种Web应用场景,在这些场景下可以充分的利用Redis的特性,大大提高效率。
链接文章这每个场景的详解
1.在主页中显示最新的项目列表。
Redis使用的是常驻内存的缓存,速度非常快。LPUSH用来插入一个内容ID,作为关键字存储在列表头部。LTRIM用来限制列表中的项目数最多为5000。如果用户需要的检索的数据量超越这个缓存容量,这时才需要把请求发送到数据库。
2.删除和过滤。
如果一篇文章被删除,可以使用LREM从缓存中彻底清除掉。
3.排行榜及相关问题。
排行榜(leader board)按照得分进行排序。ZADD命令可以直接实现这个功能,而ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。
4.按照用户投票和时间排序。
这就像Reddit的排行榜,得分会随着时间变化。LPUSH和LTRIM命令结合运用,把文章添加到一个列表中。一项后台任务用来获取列表,并重新计算列表的排序,ZADD命令用来按照新的顺序填充生成列表。列表可以实现非常快速的检索,即使是负载很重的站点。
5.过期项目处理。
使用unix时间作为关键字,用来保持列表能够按时间排序。对current_time和time_to_live进行检索,完成查找过期项目的艰巨任务。另一项后台任务使用ZRANGE...WITHSCORES进行查询,删除过期的条目。
6.计数。
进行各种数据统计的用途是非常广泛的,比如想知道什么时候封锁一个IP地址。INCRBY命令让这些变得很容易,通过原子递增保持计数;GETSET用来重置计数器;过期属性用来确认一个关键字什么时候应该删除。
7.特定时间内的特定项目。
这是特定访问者的问题,可以通过给每次页面浏览使用SADD命令来解决。SADD不会将已经存在的成员添加到一个集合。
8.实时分析正在发生的情况,用于数据统计与防止垃圾邮件等。
使用Redis原语命令,更容易实施垃圾邮件过滤系统或其他实时跟踪系统。
9.Pub/Sub。
在更新中保持用户对数据的映射是系统中的一个普遍任务。Redis的pub/sub功能使用了SUBSCRIBE、UNSUBSCRIBE和PUBLISH命令,让这个变得更加容易。
10.队列。
在当前的编程中队列随处可见。除了push和pop类型的命令之外,Redis还有阻塞队列的命令,能够让一个程序在执行时被另一个程序添加到队列。你也可以做些更有趣的事情,比如一个旋转更新的RSS feed队列。
11.缓存。
Redis缓存使用的方式与memcache相同。
网络应用不能无休止地进行模型的战争,看看这些Redis的原语命令,尽管简单但功能强大,把它们加以组合,所能完成的就更无法想象。当然,你可以专门编写代码来完成所有这些操作,但Redis实现起来显然更为轻松。
Redis 命令参考
非常不错的很详细的文章
对每个数据类型的用途有阐释,还有一些常见的问题,比较有深度,很不错
面试46道redis(事务有问题)











网友评论