データ構造の実践的な演習をやり直してください。Weibo、WeChat、ショッピングカート、宝くじアプレットがどのように使用されているかを確認してください。

システムである限り、キャッシュが存在し、ほとんどすべてのシステムがRedisから切り離せないことは誰もが知っています。これは、現在のシステムにおけるRedisの重要性を示しています。

したがって、今日はもちろん、Redisについて、主にさまざまなビジネスシナリオでのRedisの使用について説明します。

次に、キャッシングの世界から始めて、Redisの謎を段階的に解明していきましょう。

1.キャッシュ開発履歴とキャッシュ分類

1.1大規模なWebサイトでのキャッシュの使用

ファイル訪問数が多いほど、応答性が低下し、ユーザーエクスペリエンスが低下します。

キャッシュの導入、概略図は次のとおりです。

ファイル

高性能

ユーザーがデータベース内のデータに初めてアクセスする場合、このプロセスは比較的遅く、結局のところ、ハードディスクから読み取られます。ただし、ユーザーがアクセスするデータが高頻度のデータであり、頻繁に変更されない場合は、ユーザーがアクセスするデータをキャッシュに安全に保存できます。

これの利点は何ですか?これは、ユーザーが次にデータにアクセスするときに、データをキャッシュから直接取得できるようにするためです。キャッシュの操作はメモリを直接操作することであるため、速度は非常に高速です。

ただし、データベースとキャッシュ内のデータの整合性を維持するため。データベース内の対応するデータが変更された場合、キャッシュ内の対応するデータを同期的に変更できます。

高い同時実行性:

一般に、MySQLなどのデータベースのQPSは約1w(4コアおよび8g)ですが、Redisキャッシュを使用した後は、10w以上、さらには最大30w以上に到達するのは簡単です(単一マシンのredisの場合、redisクラスターは高くなる)。

QPS(Query Per Second):サーバーが1秒あたりに実行できるクエリの数。

したがって、直接操作キャッシュが耐えられるデータベース要求の数は、データベースへの直接アクセスの数よりもはるかに多いため、データベース内の一部のデータをキャッシュに転送して、ユーザーの要求の一部が直接送信されるようにすることを検討できます。データベースを経由せずにキャッシュに移動します。さらに、システムの全体的な同時実行性も向上します。

1.2共通キャッシュの分類

分散キャッシュ

分散キャッシュは主に、単一マシンのキャッシュの容量がサーバーによって制限され、一般的な情報を保存できないことを解決します。ローカルキャッシュは現在のサービスでのみ有効であるため、たとえば、2つの同一のサービスを展開する場合、それらの間でキャッシュされたデータを共有することはできません。

具有缓存功能的中间件:Redis、Memcache、Tair(阿里 、美团)等等

1.3 分布式缓存选型方案对比

Memcache和Redis区别

共同点

  1. 都是基于内存的数据库,一般都用来当做缓存使用。
  2. 都有过期策略。
  3. 两者的性能都非常高。

区别

  1. Redis 支持更丰富的数据类型(支持更复杂的应用场景)。Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。Memcached 只支持最简单的 k/v 数据类型。
  2. Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memecache 把数据全部存在内存之中。
  3. Redis 有灾难恢复机制。 因为可以把缓存中的数据持久化到磁盘上。
  4. Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 Redis 目前是原生支持 cluster 模式的.
  5. Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型。 (Redis 6.0 引入了多线程 IO )

相信看了上面的对比之后,我们已经没有什么理由可以选择使用 Memcached 来作为自己项目的分布式缓存了。

2. Redis概述&安装配置

2.1 概述

官网:redis.io

中文官网地址:www.redis.cn

ファイル 简单来说 Redis 就是一个使用 C 语言开发的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的 ,也就是它是内存数据库,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。

另外,Redis 除了做缓存之外,Redis 也经常用来做分布式锁,甚至是消息队列。

Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支持事务 、持久化、Lua 脚本、多种集群方案。

Redis应用场景

  • 缓存使用,减轻DB压力
  • DB使用,用于临时存储数据(字典表,购买记录)
  • 解决分布式场景下Session分离问题(登录信息)
  • 任务队列(秒杀、抢红包等等) 乐观锁
  • 应用排行榜 zset
  • 签到 bitmap
  • 分布式锁
  • 冷热数据交换

2.3 安装&配置

官网:redis.io/download

ファイル Redis没有官方的windows版本,所以建议在linux系统上去运行

选择下载稳定版本、不稳定版本可以尝鲜、但是不推荐在生产环境中使用

安装

第一步:安装 C 语言需要的 GCC 环境

yum install -y gcc-c++
yum install -y wget

第二步:下载并解压缩 Redis 源码压缩包

# 下载
wget https://download.redis.io/releases/redis-6.2.4.tar.gz
mkdir /usr/local/redis
    tar -zxvf redis-6.2.4.tar.gz -C /usr/local/redis

ファイル

第三步:编译 Redis 源码,进入 redis-6.2.4 目录,执行编译命令,进行安装

cd  /usr/local/redis/redis-6.2.4/src
make && make install

执行完毕后安装成功!

启动

前端启动
  • 启动命令: redis-server ,直接运行 bin/redis-server 将以前端模式启动
  • 关闭命令: ctrl+c
  • 启动缺点:客户端窗口关闭则 redis-server 程序结束,不推荐使用此方法
  • 启动图例:

ファイル

后端启动(守护进程启动)
  • 第一步:拷贝 redis-6.2.4/redis.conf 配置文件到 Redis 安装目录的 bin 目录
cp redis.conf /usr/local/redis
  • 第二步:修改 redis.conf
vim redis.conf
  • 第三步:修改 redis.conf

(1)修改daemonize no ---> daemonize yes,目的是为了让redis启动在linux后台运行

ファイル (2)修改redis的工作目录:(名称随意)

ファイル

  • 第四步:启动服务
.redis-server redis.conf

ファイル

查看进程

ファイル

  • 后端启动的关闭方式
.redis-cli shutdown

命令说明

redis-server :启动 redis 服务

redis-cli :进入 redis 命令客户端

redis-benchmark : 性能测试的工具

redis-check-aof : aof 文件进行检查的工具

redis-check-dump : rdb 文件进行检查的工具

redis-sentinel : 启动哨兵监控服务

Redis命令行客户端

  • 命令格式
.redis-cli -h 127.0.0.1 -p 6379
  • 参数说明
-h:redis服务器的ip地址
-p:redis实例的端口号
  • 默认方式:如果不指定主机和端口也可以 默认主机地址是127.0.0.1 默认端口是6379
.redis-cli

2.4 ui

命令行已经足够强大,尤其是高版本,强大到怀疑人生

但是!它并不友好,业界有很多ui可供使用,典型的:Another Redis Desktop Manager

1)开源

源码地址:gitee.com/qishibo/Ano…

编译包下载:github.com/qishibo/Ano…

2)支持多平台

Windows

Linux

Mac

3)基本使用

创建连接:

ファイル

主页监控:

ファイル

基本操作:

ファイル

命令行:

ファイル

3. 数据类型选择&应用场景

ファイル

Redis的Key的设计

1、key名设计

可读性和可管理性

以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如 业务名:表名:id

ファイル 简洁性

保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视,例如:

ファイル 不要包含特殊字符

反例:包含空格、换行、单双引号以及其他转义字符

string字符串类型

  1. 介绍 :string 数据结构是简单的 key-value 类型。虽然 Redis 是用 C 语言写的,但是 Redis 并没有使用 C 的字符串表示,而是自己构建了一种 简单动态字符串(simple dynamic string,SDS)。相比于 C 的原生字符串,Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是安全的,不会造成缓冲区溢出。
  2. 常用命令: set,get,strlen,exists,decr,incr,setex 等等。
  3. 应用场景 :一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等等。
  • 单值缓存

    SET key  value

    GET key


  • 对象缓存

    MSET user:1:name zimu user:1:balance 1888

    MGET user:1:name user:1:balance

ファイル

  • 分布式锁(「SET if Not eXists」)

    SETNX product:10001 true // 返回1代表获取锁成功

    SETNX product:10001 false // 返回0代表获取锁失败

    .......执行业务操作

    DEL product:10001 // 执行完业务 释放锁

    SET product:10001 true ex 10 nx // 防止程序意外终止导致死锁


  • 计数器

    INCR article:readcount:101

ファイル

hash类型(散列表)

ファイル

  1. 介绍 :hash 类似于 JDK1.8 前的 HashMap,内部实现也差不多(数组 + 链表)。不过,Redis 的 hash 做了更多优化。另外,hash 是一个 string 类型的 field 和 value 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以 hash 数据结构来存储用户信息,商品信息等等。
  2. 常用命令: hset,hmset,hexists,hget,hgetall,hkeys,hvals 等。
  3. 应用场景: 系统中对象数据的存储。
  • 对象缓存

    HMSET user {userId}:username zhangfei {userId}:password 123456

    HMSET user 1:username zhangfei 1:password 123456

    HMGET user 1:username 1:password

  • 电商购物车

ファイル

  • 购物车操作

    1)添加商品 ---> hset cart:1001 10088 1

    1. 增加数量 ---> hincrby cart:1001 10088 1

    3) 商品总数 ---> hlen cart:1001

    4) 删除商品---> hdel cart:1001 10088

    5)获取购物车所有商品---> hgetall cart:1001

优点:

1)同类数据归类整合储存,方便数据管理

2)相比String操作消耗内存和cpu更小

3)相比String储存 更节省空间

缺点:

1)过期功能不能使用在field上,只能用在key上

2)Redis集群架构下不适合大规模使用

ファイル

list列表类型

  1. 介绍list 即是 链表。链表是一种非常常见的数据结构,特点是易于数据元素的插入和删除并且且可以灵活调整链表长度,但是链表的随机访问困难。许多高级编程语言都内置了链表的实现比如 Java 中的 LinkedList,但是 C 语言并没有实现链表,所以 Redis 实现了自己的链表数据结构。Redis 的 list 的实现为一个 双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。
  2. 常用命令: rpush,lpop,lpush,rpop,lrange、llen 等。
  3. 应用场景: 发布与订阅或者说消息队列、慢查询。

ファイル

  • 常用数据结构

    Stack(栈)= LPUSH(左边放) + LPOP(左边取) --> FILO

    Quece(队列)= LPUSH(左边放) + RPOP右边取)

    BLocking MQ(阻塞队列)= LPUSH(左边放) + BRPOP(右边阻塞取:没有数据就阻塞!)

  • 微博、朋友圈、公众号等,关注的文章列表展示

ファイル

子慕老师关注了北京本地宝 ,京城美味君等公众号,这些订阅号发布消息时,通过推或拉的方式把消息LPUSH放入redis中属于小明的list中。其中key为msg:{小明_ID}。当小明要获取大V们发的消息时,使用LRANGE 命令从队列中获取指定个数的订阅号信息

1)京城美味君发动态,消息ID为10001

LPUSH msg:{zimu-ID} 10001

2)北京本地宝发动态,消息ID为10002

LPUSH msg:{zimu-ID} 10002

3)查看最新订阅号消息

LRANGE msg:{zimu-ID} 0 4

set集合类型

  1. 介绍 : set 类似于 Java 中的 HashSet 。Redis 中的 set 类型是一种无序集合,集合中的元素没有先后顺序。当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的。可以基于 set 轻易实现交集、并集、差集的操作。比如:你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。
  2. 常用命令: sadd,spop,smembers,sismember,scard,sinterstore,sunion 等。
  3. 应用场景: 需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景
  • 微信抽奖小程序

ファイル 1)点击 参与抽奖 加入集合

SADD key {userID}

2)查看排行榜

SMEMBERS key

3)抽取count名中奖者

SRANDMEMBER key [count] / SPOP key [count]

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

ファイル 首先了解一下set的集合操作,假如有三个集合

ファイル

交集为:SINTER set1 set2 set3 ==> { c }

并集为:SUNION set1 set2 set3 ==> { a,b,c,d,e }

差集为:SDIFF set1 set2 set3 ==> { a }

差集计算方式:set1 - (set2并set3) = {a、b、c} - {b、c、d、e} = {a} 只保留a中单独存在的元素

共同关注A的人:可以用交集来实现 我可能认识的人:可以使用差集来实现,把我关注的人求差集

sortedset有序集合类型

  1. 介绍: 和 set 相比,sorted set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。有点像是 Java 中 HashMap 和 TreeSet 的结合体。

  2. 常用命令: zadd,zcard,zscore,zrange,zrevrange,zrem 等。

  3. 应用场景: 需要对数据根据某个权重进行排序的场景。比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。

ファイル

  • Zset集合操作实现排行榜

ファイル

  1. 点击新闻,为其分值+1

ZINCRBY hotNews:20210707 1 iphone13或有日落金玫瑰金

2)展示当日排行前10

ZREVRANGE hotNews:20210707 0 ,9 WITHSCORES

bitmap位图 类型

  1. 介绍 : bitmap 存储的是连续的二进制数字(0 和 1),通过 bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 bitmap 本身会极大的节省储存空间。

ファイル 2. 常用命令: setbitgetbitbitcountbitop

  1. 应用场景: 适合需要保存状态信息(比如是否签到、是否登录...)并需要进一步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。
# SETBIT 会返回之前位的值(默认是 0)这里会生成 7 个位
127.0.0.1:6379> setbit mykey 7 1
(integer) 0
127.0.0.1:6379> setbit mykey 7 0
(integer) 1
127.0.0.1:6379> getbit mykey 7
(integer) 0
127.0.0.1:6379> setbit mykey 6 1
(integer) 0
127.0.0.1:6379> setbit mykey 8 1
(integer) 0
# 通过 bitcount 统计被被设置为 1 的位的数量。
127.0.0.1:6379> bitcount mykey
(integer) 2Copy to clipboardErrorCopied

针对上面提到的一些场景,这里进行进一步说明。

使用场景一:用户行为分析 很多网站为了分析你的喜好,需要研究你点赞过的内容。

# 记录你喜欢过 001 号小姐姐
127.0.0.1:6379> setbit beauty_girl_001 uid 1

使用场景二:统计活跃用户

面试题:现在系统有亿级的活跃用户,为了增强用户粘性,该如何实现签到、日活统计?

使用时间作为 key,然后用户 ID 为 offset,如果当日活跃过就设置为 1

那么我该如果计算某几天/月/年的活跃用户呢(暂且约定,统计时间内只有有一天在线就称为活跃),有请下一个 redis 的命令

# 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
# BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数
BITOP operation destkey key [key ...]

初始化数据:

127.0.0.1:6379> setbit 20210308 1 1
(integer) 0
127.0.0.1:6379> setbit 20210308 2 1
(integer) 0
127.0.0.1:6379> setbit 20210309 1 1
(integer) 0

统计 20210308~20210309 总活跃用户数: 1

127.0.0.1:6379> bitop and desk1 20210308 20210309
(integer) 1
127.0.0.1:6379> bitcount desk1
(integer) 1

统计 20210308~20210309 在线活跃用户数: 2

127.0.0.1:6379> bitop or desk2 20210308 20210309
(integer) 1
127.0.0.1:6379> bitcount desk2
(integer) 2

geo地理位置类型

概述

Redis 3.2 中增加了对GEO类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作

应用场景:附近的人、摇一摇、附近的车、附近银行站点查询

ファイル

环境要求

  1. redis版本需要3.2及以上
  2. 如果使用jedis操作redis,需要jedis版本为2.9及以上
  3. 如果使用spring data redis操作redis,需要spring data redis版本为1.8.0及以上

redis GEO常用命令

Tips: 在学习geo命令时会使用到经纬度坐标信息,可以在百度地图的拾取坐标系统中获取测试坐标信息,网址:api.map.baidu.com/lbsapi/getp…

1. geoadd命令

为了进行地理位置相关操作, 我们首先需要将具体的地理位置记录起来, 这一点可以通过执行 geoadd 命令来完成, 该命令的基本格式如下:

GEOADD location-set longitude latitude name [longitude latitude name ...]

此命令用于添加位置信息到集合中

以下代码展示了如何通过 GEOADD 命令, 将武汉、襄阳、宜昌、枝江、咸宁等数个湖北省的市添加到位置集合 hubeiCities 集合里面

此处添加武汉的坐标信息到hubeiCities集合中

geoadd hubeiCities 114.32538 30.534535 wuhan

此处添加襄阳、枝江、咸宁的坐标信息到hubeiCities集合中

geoadd hubeiCities 112.161882 32.064505 xiangyang 111.305197 30.708127 yichang 111.583717 30.463363 zhijiang 114.295174 29.885892 xianning

2. geopos命令

此命令用于根据输入的位置名称获取位置的坐标信息,基本语法如下

GEOPOS location-set name [name ...]

案例:查询襄阳市的位置信息

geopos hubeiCities xiangyang
--结果如下【1为经度 2为纬度】
1) "112.16188341379165649"
2) "32.06450528704699821"

也可以一次查询多个位置的经纬度

geopos hubeiCities xiangyang wuhan
--襄阳的经纬度
1) 1) "112.16188341379165649"
   2) "32.06450528704699821"
--武汉的经纬度
2) 1) "114.32538002729415894"
   2) "30.53453492166421057"

3. geodist命令

此命令用于计算两个位置之间的距离,基本语法如下:

GEODIST location-set location-x location-y [unit]

可选参数 unit 用于指定计算距离时的单位, 它的值可以是以下单位的其中一个:

m 表示单位为米。 km 表示单位为千米。 mi 表示单位为英里。 ft 表示单位为英尺。

案例:分别以默认距离单位和指定距离单位计算襄阳和武汉的距离

--不指定距离单位
127.0.0.1:6381> geodist hubeiCities xiangyang wuhan
"266889.7642"
--指定距离单位km
127.0.0.1:6381> geodist hubeiCities xiangyang wuhan km
"266.8898"

4. georadius命令和georadiusbymember命令

这两个命令都可以用于获取指定范围内的元素,也即查找特定范围之内的其他存在的地点。比如找出地点A范围200米之内的所有地点,找出地点B范围50公里之内的所有地点等等。

这两个命令的作用一样, 只是指定中心点的方式不同: georadius 使用用户给定的经纬度作为计算范围时的中心点, 而 georadiusbymember 则使用储存在位置集合里面的某个地点作为中心点。

以下是这两个命令的基本语法

GEORADIUS location-set longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]

GEORADIUSBYMEMBER location-set location radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]

这两个命令的各个参数的意义如下:

m|km|ft|mi 指定的是计算范围时的单位;

如果给定了WITHCOORD,那么在返回匹配的位置时会将位置的经纬度一并返回;

如果给定了WITHDIST , 那么在返回匹配的位置时会将位置与中心点之间的距离一并返回;

在默认情况下, GEORADIUS 和 GEORADIUSBYMEMBER 的结果是未排序的, ASC 可以让查找结果根据距离从近到远排序, 而 DESC 则可以让查找结果根据从远到近排序;

COUNT参数用于指定要返回的结果数量。

下面通过案例分别演示georadius命令和georadiusbymember命令

GEORADIUS案例: 在hubeiCities位置集合中查找距离经纬度为112.927076 28.235653(长沙)500km以内的位置信息,查找结果中应包含不超过5个位置的坐标信息,距离信息,并按距离由近到远排序。 查询代码如下:

127.0.0.1:6381> georadius hubeiCities 112.927076 28.235653 500 km withcoord withdist asc count 5
-- 咸宁  距离目标位置226.67公里  
1) 1) "xianning"
   2) "226.6716"
   3) 1) "114.29517298936843872"
      2) "29.88589217282589772"
-- 枝江  距离目标位置279.91公里
2) 1) "zhijiang"
   2) "279.9154"
   3) 1) "111.58371716737747192"
      2) "30.46336248623112652"
-- 武汉  距离目标位置289.38公里
3) 1) "wuhan"
   2) "289.3798"
   3) 1) "114.32538002729415894"
      2) "30.53453492166421057"
-- 宜昌  距离目标位置316.68公里
4) 1) "yichang"
   2) "316.6777"
   3) 1) "111.30519658327102661"
      2) "30.70812783498269738"
-- 襄阳  距离目标位置432.18公里
5) 1) "xiangyang"
   2) "432.1767"
   3) 1) "112.16188341379165649"
      2) "32.06450528704699821"

GEORADIUSBYMEMBERの場合:hubeiCitiesロケーションコレクションで襄陽から200km以内のロケーション情報を検索します[ここで指定するターゲットロケーションはhubeiCitiesに存在するロケーションのみですが、ロケーション座標は指定できません]。検索結果には次の座標が含まれている必要があります。 2つ以下の場所情報、距離情報、および遠から近くまでの距離でソートされます。クエリコードは次のとおりです。

127.0.0.1:6381> georadiusbymember hubeiCities xiangyang 200 km withcoord withdist desc count 2
-- 枝江  距襄阳186.38km
1) 1) "zhijiang"
   2) "186.3784"
   3) 1) "111.58371716737747192"
      2) "30.46336248623112652"
-- 宜昌  距襄阳171.40km
2) 1) "yichang"
   2) "171.3950"
   3) 1) "111.30519658327102661"
      2) "30.70812783498269738"

さて、今日はここでやめます。単語のコーディングの難しさの深い意味をますます理解するようになりました。誤って6000以上の単語を入力したため、少し疲れました。

役に立ったら、いいね、コメント、再投稿、そしてワンクリックと3つのリンクでフォローアップしてください、ハハハ

あなたのサポートが私の最大のモチベーションです。

さあ、労働者を殴ってください!

過去の記事、誰もが自分で飲むことができます。

過去の乾物:

この記事は、Chuanzhi Education Boxue Valley-Wild Architectの教育研究チームによって公開されました。この記事が役に立った場合は、フォローして気に入ってください。提案があれば、コメントやプライベートレターを残すこともできます。サポートは私が創作を続ける原動力です。出典を教えてください!

おすすめ

転載: juejin.im/post/7120480364065193998