数据结构与内存管理策略(上)

  • 时间:
  • 浏览:0
  • 来源:大发时时彩网页计划—大发快三彩票

这俩 你们儿儿使用 5 种数据类型来缓存数据,否则 redis 会根据你们儿儿存储数据的不同而挑选 不同的数据特性和编码。

redis 为你们儿儿提供了 5 种数据类型,基本上你们儿儿使用频率最高的也不 string ,而对许多这俩 数据类型使用的频次稍弱于 string

stringredis 提供的字符串类型。都时需针对 string 类型独立设置 expire time 。通常用来存储长字符串数据,比如,某个对象的 json 字符串。

这里你们儿儿不打算罗列这 5 种数据类型的使用方式,那此资料网上有也不 。你们儿儿主要讨论这 5 种数据类型的功能特点,那此特点分别适合用于补救那此现实的业务场景,最重要的是你们儿儿如何组合性的使用这 5 种数据类型来补救复杂的 cache 那此的什么的问题。

那此 string:order:{orderId} 字符串 key 暂且一定是为了服务这俩 场景,也不 整个系统最底层的数据,各种场景最后都时需获取那此数据。那此 set 集合都时需认为是查询条件数据,用来辅助查询条件的计算。

string 类型你们儿儿在使用上最巧妙的是都时需动态拼接 key__。通常你们儿儿都时需将一组 __id 放上 set 里,否则动态查找 string 还否有 所处,由于不所处说明由于过期由于由于数据修改主动 delete 了,时需再做一次 cache 数据 load

支付 gateway 收到 callback 时候不做任何补救直接交给 分发器 。___分发器___ 是二个多 多多无清况 的 cluster ,每个 node 通过向 注册中心 pull handler queue list ,也也不 获取下游补救器注册到注册中心里的消息通道。

你们儿儿先来分析二个多 多多查询接口蕴含 高的常规信息。

在大促的时候时需展现团购列表,这俩 接口的访问量是非常大的,团购活动时需根据参团人数倒序排序,否则分页返回指定数量的团列表。

否则复杂点的场景时需多个 set 集合来支撑计算,在 redis 服务器 里由于会有也不 这类原先的集合。

同样二个多 多多 key ,否则由于你们儿儿设置的值不同而 redis 挑选 了不同的内存数据特性和编码。这俩 redis 提供的 string 数据类型,否则 redis 会自动识别你们儿儿 cache 的数据类型是 int 还是 string

简单动态字符串简称 SDS ,在 redis 中所有涉及到字符串的地方完全都有使用 SDS 实现,当然这里不包括字面量。 SDS 与传统 C 字符串的区别也不 SDS 是特性化的,它都时需高效的补救分配、回收、长度计算等那此的什么的问题。

Redis 数据类型特点与使用场景

由于有时需对某个字段进行修改,使用 string 很明显是会多出也不 开销,时需读取出来反序列化成对象否则操作,否则再序列化写回 redis ,这里面由于还有并发那此的什么的问题。

你们儿儿日常使用的是 redis 提供的 5 种数据类型,否则这 5 种数据类型在内存中的数据特性和编码有也不 种。随着你们儿儿存储的数据类型的不同、数据量的大小不同都有引起内存数据特性的动态调整。

java fork/join 框架使用并行来提高性能,否则会带来由于并发 take task 带来的 race condition (竞态条件) 那此的什么的问题,也不 采用 work-stealing 算法 来补救由于竞争那此的什么的问题带来的性能损耗。

上图使用 hash 数据类型来记录页面的 a/b metrics ,左边的是首页 index 的各个区域的统计,右边是营销 marketing 的各个区域统计。

你们儿儿假设这俩 接口名为 getTopGroups(getTopGroupsRequest request)

再看根据参团人数排序那此的什么的问题,你们儿儿立刻就都时需想到使用 zset 来补救团排序那此的什么的问题,由于要能一个多 多多多排序维度,也不 二个多 多多 zset 就够了。你们儿儿使用二个多 多多 __zset__来缓存所有团的参团人数集合,它是二个多 多多全量的团排序集合。

这非常适合实现这类 Java Concurrency Fork/Join 框架中的 work-stealing 算法 (工作窃取)

那此集合你们儿儿都时需称为 功能数据__,那此数据是用来辅助 __cache 计算的,当进行各种集合运算之都有得出当前查询时需返回的子集,最后你们儿儿才会去获取某个订单真正的数据。

除了使用 OBJECT encoding 命令外,你们儿儿还都时需使用 DEBUG OBJECT 命令来查看更多完全信息。

set 最大的特点也不 集合的计算能力,___inter 交集___、___union 并集___、___diff 差集___,那此特点都时需用来做高性能的交叉计算由于剔除数据。

每二个多 多多分发器 node 会维护二个多 多多本地 queue list ,否则顺序推送消息到那此 queue list 即可。这里会一阵一阵小那此的什么的问题,也不 支付 gateway 调用分发器的时候是如何做 load balance ,由于完全都有平均负载由于会有某个 queue list 高出许多 queue list

一方面由于 string 使用起来比较简单,都时需方便存储复杂大对象,使用场景比较多。还二个多 多多多由于也不 由于 redis expire time 要能设置在 key 上,像 list__、__hash__、__set__、__zset 属于集合类型,会管理一组 item__,你们儿儿无法在那此集合的 __item 上设置过期时间,也不 使用 expire time 来补救集合的 cache 失效会变得稍微复杂些。否则 string 使用 expire time 来管理过期策略会比较简单,由于它蕴含 的项少。这里说的集合是宽泛的这类集合。

set 集合数据类型都时需支持集合运算,要能存储重复数据。

query condition

下面你们儿儿分享二个多 多多使用多个 zset 、__string__ 来优化 团购系统 前台接口的例子。由于篇幅和时间限制,这里只介绍跟本次案例相关的信息。

这是 redis 3.0 版本的 sds.h 头文件定义,__3.0.0__ 时候变化比较大。__len__ 表示字符串长度,__free__ 表示空间长度,__buf__ 数组表示字符串。

在许多比较特殊的场合由于时需组合排序,由于有多个 zset 分别用来对同二个多 多多实体在不同维度的排序,按时间排序、按人数排序等。这俩 时候就都时需组合使用 zset 带来的便捷性,利用 pipeline 再结合多个 zset 最终得出组合排序集合。

page

你们儿儿来看下完全的流程,如何补救查询、排序、分页的。

hash 数据类型的特点通常都时需用来补救蕴含 映射关系,并肩又时需对许多项进行更新由于删除等操作。由于完全都有某个项时需维护,这样一般都时需通过使用 string 来补救。

hash 数据类型很明显是基于 hash 算法的,对于项的查找时间复杂度是 O(1) 的,在极端清况 下由于突然总出 项 hash 冲突那此的什么的问题,__redis__ 外部是使用链表加 key 判断来补救的。具体 redis 外部的数据特性你们儿儿在里面有介绍,这里就不展开了。

Redis 持久化方式

查询条件,companyid=1000,sellerid=1010101 诸这样类。

这俩 zset 在你们儿儿应用系统中能用到地方到处完全都有,这里你们儿儿举二个多 多多简单的例子,在团购系统中你们儿儿通常时需根据参团人数来排序成团列表,你们儿儿都希望参加那此即将成团的团。

使用 redis hash increment 进行原子增加操作。__HINCRBY__ 命令都时需原子增加任何给定的整数,也都时需通过 HINCRBYFLOAT 来原子增加浮点类型数据。

redis 3.2.0 版本的时候引入了 quicklist 链表特性,结合了 linkedlistziplist 的优势。

由于篇幅和时间关系,这里就不展开越来太久的业务场景介绍了。这其中还涉及到计算 cache 过期时间的那此的什么的问题,这也跟促销活动的运营规则有关系,还涉及到有由于 query condition hash 冲突那此的什么的问题等,否则那此由于不与你们儿儿本节主题相关。

有了返回的团 code 集合时候就都时需通过 mget 来批量获取 string 类型的团详情信息,这里就不贴出代码了。

上图是二个多 多多根据团购code创建的zset,___score 分值___ 也不 参团人数累加和。

zset 这俩 提供了也不 方式用来进行集合的排序,由于时需 score 分值都时需使用 withscore 字句带出每一项的分值。

Redis 内存数据特性与编码

由于这里你们儿儿纯粹用 redis 来提高 cache 能力,不涉及到有关于任何搜索的能力,也不 这里忽略许多复杂查询的清况 。这俩 你们儿儿在复杂的地方使用了 elastcsearch 来提高搜索能力。

你们儿儿由于了解了 redis 提供的 5 种数据类型,这样 redis 外部到底是如何支持这 5 种数据类型的,也也不 说 redis 到底是使用那此样的数据特性来存储、查找你们儿儿设置在内存中的数据。

原先们都时需使用 redis hash 提供的实体属性 hash 存储特性,你们儿儿都时需认为 hash value 是二个多 多多 hash table ,实体的每二个多 多多属性完全都有通过 hash 得到属性的最终数据索引。

标签: Redis Redis数据特性 Redis内存管理策略 Redis数据类型 Redis类型映射

你们儿儿知道使用 type 命令都时需查看某个 key 否有 5 种数据类型之一,否则当你们儿儿想查看某个 key 底层是使用哪种数据特性和编码来存储的时候都时需使用 OBJECT encoding 命令。

你们儿儿来仔细分析下,首先不同的查询条件从 DB 里查询出来的数据是不一样的,也也不 说查询出来的团列表是不一样的,由于有 company 公司 、___channel 渠道___ 等过滤条件。由于二个多 多多团购活动下不需要有越来太久团,顶多上百个是极限了,也不 二个多 多多查询条件出来的团列表也顶多几二个,否则根据场景分析热点查询条件不需要超过二个,也不 你们儿儿挑选 将 查询条件 hash 出二个多 多多 code 来缓存本次查询条件的全量团列表集合,否则那此结果集是这样任何排序的。

通过对由于排序时候的团列表 zset 使用 zrange 来获取出分页集合。

Redis 内存管理策略

list-compress-depth:控制链表两端节点的压缩个数,越是靠近两端的节点被访问的机率越大,也不 都时需将访问机率大的节点不压缩,许多节点进行压缩

这俩 set 无法设置 item 的过期时间,否则你们儿儿都时需将 set itemstring key 关联来达到相同的效果。

quicklist 提供了灵活性并肩也兼顾了 ziplist 的压缩能力,__quicklist->encoding__ 指定了这俩 压缩算法。 quicklist->compress 表示你们儿儿都时需进行 quicklist node 的宽度压缩能力。redis 提供了二个多 多多有关于压缩的配置。

你们儿儿总结了 redis 提供的 5 种数据类型的各人特点和一般的使用场景。否则你们儿儿不仅仅都时需分始于英语 了了用那此数据类型,你们儿儿完也不 时需综合使用那此数据类型来完成复杂的 cache 场景。

你们儿儿都时需抽象出这几个 维度的信息:

排序信息,一般是默认二个多 多多列排序,否则在复杂的场景下会有由于让接口使用者定制排序字段,比如许多租户信息列。

上图从 query condition 计算 hash code ,否则通过 DB 查询出当前条件全量团列表。

zset:marketing:groupon:hottop:available:group key 表示全量团的参团人数,用二个多 多多 zset 来缓存。接着将这二个多 多多 zset 计算交集,就都时需得出当前查询所时需的蕴含 参团人数的 zset ,最后在使用 zrevrange 获取分页区间。

list-max-ziplist-size:ziplist长度控制

list 在提高 throughput 的场景中非常适用,由于它特有的 LPUSH__、__RPUSH__、__LPOP__、__RPOP 功能都时需无缝的支持生产者、消费者架构模式。

zset 排序集合与 set 集合这类,否则 zset 提供了排序的功能。在介绍 set 集合的时候你们儿儿知道 set 集合中的成员是无序的,__zset__ 填补了集合都时需排序的空隙。

zset 最强大的功能也不 都时需根据某个 score 比分值 进行排序,这在也不 业务场景中非常急需。比如,在促销活动里根据商品的销售数量来排序商品,在旅游景区里根据流入人数来排序热门景点等。

当然,下架的时候都时需直接删除缓存的活动商品,否则活动是从 marketing 系统中 load 出来的,就算我将 cache 里的活动商品删除,当下次再从 marketing 系统中 load 活动商品时候还是会有下架商品。当然这也不 举例,二个多 多多场景有不同的实现方式。

基本上你们儿在做任何事情都时需根据许多条件进行排序。

由于你们儿儿设置的是字符串,且这俩 字符串长度不大于 39 字节这样将使用 embstr 来编码,由于大于 39 字节将使用 raw 来编码。__redis 4.0__ 将这俩 阀值扩大了 45 个字节。

DEBUG OBJECT 能想看 这俩 对象的 refcount 引用计数 、___serializedlength 长度___ 、___lru_seconds_idle 时间___ ,那此信息决定了这俩 key 缓存清除策略。

上图中的左边是二个多 多多 keyset:order:idsset 集合,它由于是二个多 多多全量集合,也由于是某个查询条件获取出来的二个多 多多集合。

redis 为你们儿儿提供了 TYPE 命令来查看某个 key 的数据类型,如:__string__ 类型:

SDS 有也不 优点,比如,获取长度的时间复杂度 O(1) ,不时需遍历所有 char buf[] 组数,直接返回 len 值。

redis list 的 LPUSH__、__RPUSH__、__LPOP__、__RPOP 特性这俩 都时需在也不 场景下提高这俩 横向扩展计算能力。

本节也不 做数据特性和编码的一般性介绍,不做越来太久细节讨论,一方面是关于 redis 源码分析的资料网上有也不 ,还二个多 多多多由于也不 redis 每二个多 多多版本的实现有很大差异,一旦展开细节讨论每二个多 多多点每二个多 多多数据特性都有很复杂,也不 你们儿儿这里就不展开讨论那此,也不 起到抛砖引玉作用。

首先二个多 多多查询接口肯定是有 query condition 查询条件 ,否则是 sort 排序信息_ 、最后是 page 分页信息_ 。这是一般接口所承担的基本职责,当然,特殊场景下还时需支持 master/slave replication 时关于数据 session 一致性 的要求,时需提供跟踪标记来回 master 查询数据,这里就不展开了。

当然还有空间分配检查、空间预分配、空间惰性释放等,那此完全都有 SDS 特性化字符串带来的强大的扩展能力。

上图中左右两边是二个多 多多不同的集合,左边是营销域中的可用商品ids集合,右边是营销域中活动商品ids集合,里面计算出二个多 多多集合的交集。

由于 redisSignle-Thread 单系统进程模型 ,基于这俩 特性你们儿儿就都时需使用 redis 提供的 pipeline 管道 来提交一连串蕴含 逻辑的命令集合,那此命令在补救期间不需要被许多客户端的命令干扰。

由于你们儿儿习惯性的使用 string 而忽视许多这俩 数据类型的原先宽度次由于,大多由于你们儿儿对另外这俩 数据类型的使用和原理完全都有太了解。这俩 时候往往会忽视在特定场景下使用这俩 数据类型由于会比 string 性能高出也不 ,比如使用 hash 特性来提高某个实体的某个项的修改等。

上图中模拟了二个多 多多典型的支付 callback 峰值场景。在峰值突然总出 的地方一般你们儿儿都有使用加 buffer 的方式来加快请求补救下行下行速率 ,原没还上能提高并发补救能力,提高 throughput

在系统进程里你们儿儿都时需很方便的使用 redisatomic 特性对 hash 某个项进行累加操作。

分页信息,简单理解也不 数据记录排完序时候的第几行到第几行。

sort

链表数据特性你们儿儿是比较熟悉的,最大的特点也不 节点的增、删非常灵活。__redis List__ 数据类型底层也不 基于链表来实现。这是 redis 3.0 实现。

而分发器不时需做 soft load balance ,由于哪怕某个 queue list 比许多 queue list 多也无所谓,由于下游 message handler 会根据 work-stealing 算法来窃取许多消费慢的 queue list

set 集合在使用场景上还是比较多和自由的。举个简单的例子,在应用系统中比较常见的也不 商品、活动类场景。用二个多 多多 set 缓存有效商品集合,再用二个多 多多 set 缓存活动商品集合。由于商品突然总出 上下架操作只时需维护有效商品 set ,每次获取活动商品的时候时需过滤下否有 有下架商品,由于有就时需从活动商品中剔除。

在许多复杂的场景中,也都时需使用 SINTERSTORE 命令将交集计算后的结果存储在二个多 多多目标集合中。 这在使用 pipeline 命令管道中一阵一阵有用,将 SINTERSTORE 命令邮包裹邮寄邮寄在 pipeline 命令串中都时需重复使用计算出来的结果集。

hot-top 接口是指热点、排名接口的意思,表示它的浏览量、并发量比较高,一般大促的时候都有有几个 这俩 性能要求比较高的接口。

上述你们儿儿分析总结出了二个多 多多查询接口的基本信息,这里还二个多 多多多有关于高并发接口的设计原则也不 将 hot-top 接口和一般 search 接口分离开,由于要能分而治之要能分别根据特点挑选 不同的技术。由于你们儿儿不分职责将所有的查询场景封塞进二个多 多多接口里,这样在里面优化接口性能的时候基本就很麻烦了,许多场景是无法由于没能用 cache 来补救的,由于接口里耦合了各种场景逻辑,就算勉强能实现性能也不 会高。

对比 redis 3.2quicklistredis 3.0 ,很明显 quicklist 提供了更加充沛的压缩功能。__redis 3.0__ 的版本是每个 listnode 直接缓存值,而 quicklistnode 还有强大的有关于压缩能力。

前面做那此铺垫是为了能在介绍案例的时候达成二个多 多多基本的共识。现在你们儿儿来看下这俩 团购系统的 hot-top 接口的具体逻辑。

这样你们儿儿如何将用户的查询条件出来的团列表根据参团人数排序尼,刚好都时需使用 zset 的交集运算直接计算出当前这俩 集合的 zset 子集。