本文共 6475 字,大约阅读时间需要 21 分钟。
下载地址:http://redis.io/download安装步骤:# 安装gccyum install gcc# 把下载好的redis‐5.0.3.tar.gz放在/usr/local文件夹下,并解压wget http://download.redis.io/releases/redis‐5.0.3.tar.gztar xzf redis‐5.0.3.tar.gzcd redis‐5.0.3# 进入到解压好的redis‐5.0.3目录下,进行编译与安装make# 修改配置daemonize yes #后台启动protected‐mode no #关闭保护模式,开启的话,只有本机才可以访问redis# 需要注释掉bind#bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)# 启动服务src/redis‐server redis.conf# 验证启动是否成功ps ‐ef | grep redis# 进入redis客户端src/redis‐cli# 退出客户端quit# 退出redis服务:(1)pkill redis‐server(2)kill 进程号(3)src/redis‐cli shutdown
字符串常用操作SET key value //存入字符串键值对MSET key value [key value ...] //批量存储字符串键值对SETNX key value //存入一个不存在的字符串键值对GET key //获取一个字符串键值MGET key [key ...] //批量获取字符串键值DEL key [key ...] //删除一个键EXPIRE key seconds //设置一个键的过期时间(秒)原子加减INCR key //将key中储存的数字值加1DECR key //将key中储存的数字值减1INCRBY key increment //将key所储存的值加上incrementDECRBY key decrement //将key所储存的值减去decrement
单值缓存
SET key value GET key
对象缓存
- SET user:1 value(json格式数据)
- MSET user:1:name zhuge user:1:balance 1888 MGET user:1:name user:1:balance
分布式锁(简易性的不能生产直接使用)
SETNX product:10001 true //返回1代表获取锁成功 SETNX product:10001 true //返回0代表获取锁失败 。。。执行业务操作 DEL product:10001 //执行完业务释放锁 SET product:10001 true ex 10 nx //防止程序意外终止导致死锁
计数器
INCR article:readcount:{文章id} GET article:readcount:{文章id}
Web集群session共享
spring session + redis实现session共享
分布式系统全局序列号(一次性来加1000个id,本地成功后,就可以本机控制这100个id)
INCRBY orderId 1000 //redis批量生成序列号提升性能
Hash常用操作HSET key field value //存储一个哈希表key的键值HSETNX key field value //存储一个不存在的哈希表key的键值HMSET key field value [field value ...] //在一个哈希表key中存储多个键值对HGET key field //获取哈希表key对应的field键值HMGET key field [field ...] //批量获取哈希表key中多个field键值HDEL key field [field ...] //删除哈希表key中的field键值HLEN key //返回哈希表key中field的数量HGETALL key //返回哈希表key中所有的键值HINCRBY key field increment //为哈希表key中field键的值加上增量increment
对象缓存
HMSET user {userId}:name zhuge {userId}:balance 1888 HMSET user 1:name zhuge 1:balance 1888 HMGET user 1:name 1:balance 这样存储的好处,可以在对象某个属性变更的时候,不要讲user整个value替换,只需要替换里面的field对应的value
电商购物车
- 以用户id为key
- 商品id为field
- 商品数量为value
购物车操作
添加商品 hset cart:1001 10088 1 增加数量 hincrby cart:1001 10088 1 商品总数 hlen cart:1001 删除商品 hdel cart:1001 10088 获取购物车所有商品 hgetall cart:1001
优缺点对比
优点
- 同类数据归类整合储存,方便数据管理
- 相比string操作消耗内存与cpu更小
- 相比string储存更节省空间
缺点
过期功能不能使用在field上,只能用在key上 Redis集群架构下不适合大规模使用
List常用操作LPUSH key value [value ...] //将一个或多个值value插入到key列表的表头(最左边)RPUSH key value [value ...] //将一个或多个值value插入到key列表的表尾(最右边)LPOP key //移除并返回key列表的头元素RPOP key //移除并返回key列表的尾元素LRANGE key start stop //返回列表key中指定区间内的元素,区间以偏移量start和stop指定BLPOP key [key ...] timeout //从key列表表头弹出一个元素,若列表中没有元素,阻塞等待 timeout秒,如果timeout=0,一直阻塞等待BRPOP key [key ...] timeout //从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待 timeout秒,如果timeout=0,一直阻塞等待
常用分布式场景的数据结构
Stack(栈) = LPUSH + LPOP Queue(队列)= LPUSH + RPOP Blocking MQ(阻塞队列)= LPUSH + BRPOP
微博消息和微信公号消息(push的方式,其实还是pull的方式)
小王(我)关注了李佳琪,王思聪
- 李佳琪发微博,消息ID为10018 LPUSH msg:{小王-ID} 10018
- 王思聪发微博,消息ID为10086 LPUSH msg:{小王-ID} 10086
- 小王查看最新4条微博消息 LRANGE msg:{小王-ID} 0 4
Set常用操作SADD key member [member ...] //往集合key中存入元素,元素存在则忽略, 若key不存在则新建SREM key member [member ...] //从集合key中删除元素SMEMBERS key //获取集合key中所有元素SCARD key //获取集合key的元素个数SISMEMBER key member //判断member元素是否存在于集合key中SRANDMEMBER key [count] //从集合key中选出count个元素,元素不从key中删除SPOP key [count] //从集合key中选出count个元素,元素从key中删除Set运算操作SINTER key [key ...] //交集运算SINTERSTORE destination key [key ..] //将交集结果存入新集合destination中SUNION key [key ..] //并集运算SUNIONSTORE destination key [key ...] //将并集结果存入新集合destination中SDIFF key [key ...] //差集运算SDIFFSTORE destination key [key ...] //将差集结果存入新集合destination中
微信抽奖小程序
- 点击参与抽奖加入集合 SADD key {userlD}
- 查看参与抽奖所有用户 SMEMBERS key
- 抽取count名中奖者 SRANDMEMBER key [count] // 不会将抽中的key移除,允许重复中奖 SPOP key [count] //抽中后会移除,避免重复中奖
微信微博点赞,收藏,标签
- 点赞 SADD like:{消息ID} {用户ID}
- 取消点赞 SREM like:{消息ID} {用户ID}
- 检查用户是否点过赞 SISMEMBER like:{消息ID} {用户ID}
- 获取点赞的用户列表 SMEMBERS like:{消息ID}
- 获取点赞用户数 SCARD like:{消息ID}
SINTER set1 set2 set3 -> { c } //取交集
SUNION set1 set2 set3 -> { a,b,c,d,e } // 取并集 SDIFF set1 set2 set3 -> { a } //以第一个set1为基准,去除在set2和set3中的元素集合操作实现微博微信关注模型
- 小王关注的人: 小王Set-> {小李, 小张}
- 小张关注的人: 小张Set–> {小红, 小王, 小李, 小云}
- 小李关注的人: 小李Set-> {小红, 小王, 小天, 小周, 小狗)
- 我和小张共同关注: SINTER 小王Set 小张Set–> {小李}
- 我关注的人也关注他(小李): SISMEMBER 小张Set 小李
- 我可能认识的人: SDIFF 小李Set 小王Set->(小红, 小王, 小天, 小周, 小狗}
电商品类搜索
SADD brand:huawei P40 SADD brand:xiaomi mi-10 SADD brand:iPhone iphone12 SADD os:android P40 mi-10 SADD cpu:brand:intel P40 mi-10 SADD ram:8G P40 mi-10 iphone12 SINTER os:android cpu:brand:intel ram:8G {P40,mi-10}
ZSet常用操作ZADD key score member [[score member]…] //往有序集合key中加入带分值元素ZREM key member [member …] //从有序集合key中删除元素ZSCORE key member //返回有序集合key中元素member的分值ZINCRBY key increment member //为有序集合key中元素member的分值加上increment ZCARD key //返回有序集合key中元素个数ZRANGE key start stop [WITHSCORES] //正序获取有序集合key从start下标到stop下标的元素ZREVRANGE key start stop [WITHSCORES] //倒序获取有序集合key从start下标到stop下标的元素Zset集合操作ZUNIONSTORE destkey numkeys key [key ...] //并集计算ZINTERSTORE destkey numkeys key [key …] //交集计算
Zset集合操作实现排行榜
- 点击新闻 ZINCRBY hotNews:20190819 1 张雨剑吴倩带女儿出游
- 展示当日排行前十 ZREVRANGE hotNews:20190819 0 9 WITHSCORES
- 七日搜索榜单计算 ZUNIONSTORE hotNews:20190813-20190819 7 hotNews:20190813 hotNews:20190814… hotNews:20190819
- 展示七日排行前十 ZREVRANGE hotNews:20190813-20190819 0 9 WITHSCORES
redis整个应用肯定不是单线程的,只是redis的网络IO和键值对的读写(命令的执行)是有一个线程来完成的。这也是redis对外提供存储的主要流程。
但是redis的其他功能例如,持久化、异步清除过期key,集群同步等都是其他线程完成的
因为全部数据都在内存中,内存的操作非常快。没必要多线程,如果多线程反而会有线程切换带来的成本。 多线程的提升利小于多线程切换的弊
也正是因为redis核心流程为单线程,所以要避免使用 keys * 之类的操作,避免一次扫描大量的key。因为 此时会阻塞线程。导致其他客户端不可用。
redis 底层用的是IO多路复用。利用epoll模型实现IO多路复用。即将连接信息和时间放到队列里。一次放到文件分派器,时间分派器将事件分发给事件处理器
NIO多路复用在很多源码中都用到,例如netty、zk通讯后面我在写zk和netty源码的时候在分享代码。<毕竟redis的C语言还是比较吃力>
keys 会全量遍历key。按照特定的正则字符串去匹配扫描所有的key。如果redis中的数据量非常多是,性能非常的差。线上严禁使用
SCAN cursor [MATCH pattern] [COUNT count]
cursor 游标,整数值,就是hash桶的索引值(底层这些key全部存在hashMap中),即使hashMap中数组的下标。每次扫描返回结果中会带有下次该扫描的游标,第一次扫描必须从0开始
pattern 需要遍历的正则表达式,即你扫描key的条件 count 每次扫描多少个元素(注意不是扫描返回多少个元素)
注意:整个扫描的过程并不是一定100%准确的。因为扫描其实就是将hashMap上每个桶的链表上的数据按照你指定的一个个匹配。
已经扫描过的桶是不会在扫描的。因为是hashMap肯定会有reHash的过程,在其他客户端同时的增删key,就会导致reHash或者新增、删除的key位于已扫描的桶,那么不会被扫描出来。所以scan不是非常精准的。 不应该哪来做强依赖性的业务操作。
转载地址:http://vlinz.baihongyu.com/