博客
关于我
redis ① redis安装&核心数据结构&高性能原理
阅读量:524 次
发布时间:2019-03-07

本文共 6475 字,大约阅读时间需要 21 分钟。

一、redis安装

下载地址: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

二、核心数据结构

在这里插入图片描述

String结构

字符串常用操作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

String 应用场景

单值缓存

SET key value
GET key

对象缓存

  1. SET user:1 value(json格式数据)
  2. 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结构

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

hash的应用场景

对象缓存

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

电商购物车

  1. 以用户id为key
  2. 商品id为field
  3. 商品数量为value

购物车操作

添加商品 hset cart:1001 10088 1
增加数量 hincrby cart:1001 10088 1
商品总数 hlen cart:1001
删除商品 hdel cart:1001 10088
获取购物车所有商品 hgetall cart:1001

优缺点对比

优点

  1. 同类数据归类整合储存,方便数据管理
  2. 相比string操作消耗内存与cpu更小
  3. 相比string储存更节省空间

缺点

过期功能不能使用在field上,只能用在key上
Redis集群架构下不适合大规模使用

列表list结构

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,一直阻塞等待

list应用场景

常用分布式场景的数据结构

Stack(栈) = LPUSH + LPOP
Queue(队列)= LPUSH + RPOP
Blocking MQ(阻塞队列)= LPUSH + BRPOP

微博消息和微信公号消息(push的方式,其实还是pull的方式)

小王(我)关注了李佳琪,王思聪

  1. 李佳琪发微博,消息ID为10018
    LPUSH msg:{小王-ID} 10018
  2. 王思聪发微博,消息ID为10086
    LPUSH msg:{小王-ID} 10086
  3. 小王查看最新4条微博消息
    LRANGE msg:{小王-ID} 0 4

结合set结构

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中

set 应用场景

微信抽奖小程序

  1. 点击参与抽奖加入集合
    SADD key {userlD}
  2. 查看参与抽奖所有用户
    SMEMBERS key
  3. 抽取count名中奖者
    SRANDMEMBER key [count] // 不会将抽中的key移除,允许重复中奖
    SPOP key [count] //抽中后会移除,避免重复中奖

微信微博点赞,收藏,标签

  1. 点赞
    SADD like:{消息ID} {用户ID}
  2. 取消点赞
    SREM like:{消息ID} {用户ID}
  3. 检查用户是否点过赞
    SISMEMBER like:{消息ID} {用户ID}
  4. 获取点赞的用户列表
    SMEMBERS like:{消息ID}
  5. 获取点赞用户数
    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中的元素

在这里插入图片描述

集合操作实现微博微信关注模型

  1. 小王关注的人:
    小王Set-> {小李, 小张}
  2. 小张关注的人:
    小张Set–> {小红, 小王, 小李, 小云}
  3. 小李关注的人:
    小李Set-> {小红, 小王, 小天, 小周, 小狗)
  4. 我和小张共同关注:
    SINTER 小王Set 小张Set–> {小李}
  5. 我关注的人也关注他(小李):
    SISMEMBER 小张Set 小李
  6. 我可能认识的人:
    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结构

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应用场景

在这里插入图片描述

Zset集合操作实现排行榜

  1. 点击新闻
    ZINCRBY hotNews:20190819 1 张雨剑吴倩带女儿出游
  2. 展示当日排行前十
    ZREVRANGE hotNews:20190819 0 9 WITHSCORES
  3. 七日搜索榜单计算
    ZUNIONSTORE hotNews:20190813-20190819 7
    hotNews:20190813 hotNews:20190814… hotNews:20190819
  4. 展示七日排行前十
    ZREVRANGE hotNews:20190813-20190819 0 9 WITHSCORES

三、高性能原理

redis是单线程吗?

redis整个应用肯定不是单线程的,只是redis的网络IO和键值对的读写(命令的执行)是有一个线程来完成的。这也是redis对外提供存储的主要流程。

但是redis的其他功能例如,持久化、异步清除过期key,集群同步等都是其他线程完成的

redis核心流程是单线程的为什么还这么快

因为全部数据都在内存中,内存的操作非常快。没必要多线程,如果多线程反而会有线程切换带来的成本。 多线程的提升利小于多线程切换的弊

也正是因为redis核心流程为单线程,所以要避免使用 keys * 之类的操作,避免一次扫描大量的key。因为 此时会阻塞线程。导致其他客户端不可用。

redis单线程是如何做到并发连接客户端

redis 底层用的是IO多路复用。利用epoll模型实现IO多路复用。即将连接信息和时间放到队列里。一次放到文件分派器,时间分派器将事件分发给事件处理器

NIO多路复用在很多源码中都用到,例如netty、zk通讯后面我在写zk和netty源码的时候在分享代码。<毕竟redis的C语言还是比较吃力>

一些高级命令

keys 会全量遍历key。按照特定的正则字符串去匹配扫描所有的key。如果redis中的数据量非常多是,性能非常的差。线上严禁使用

利用scan 渐进式的遍历健

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/

你可能感兴趣的文章
mysql cmake 报错,MySQL云服务器应用及cmake报错解决办法
查看>>
Multiple websites on single instance of IIS
查看>>
mysql CONCAT()函数拼接有NULL
查看>>
multiprocessing.Manager 嵌套共享对象不适用于队列
查看>>
multiprocessing.pool.map 和带有两个参数的函数
查看>>
MYSQL CONCAT函数
查看>>
multiprocessing.Pool:map_async 和 imap 有什么区别?
查看>>
MySQL Connector/Net 句柄泄露
查看>>
multiprocessor(中)
查看>>
mysql CPU使用率过高的一次处理经历
查看>>
Multisim中555定时器使用技巧
查看>>
MySQL CRUD 数据表基础操作实战
查看>>
multisim变压器反馈式_穿过隔离栅供电:认识隔离式直流/ 直流偏置电源
查看>>
mysql csv import meets charset
查看>>
multivariate_normal TypeError: ufunc ‘add‘ output (typecode ‘O‘) could not be coerced to provided……
查看>>
MySQL DBA 数据库优化策略
查看>>
multi_index_container
查看>>
MySQL DBA 进阶知识详解
查看>>
Mura CMS processAsyncObject SQL注入漏洞复现(CVE-2024-32640)
查看>>
Mysql DBA 高级运维学习之路-DQL语句之select知识讲解
查看>>