Redis第1讲——入门简介

Java并发编程的总结和学习算是告一段落了,这段时间思来想去,还是决定把Redis再巩固和学习一下。毕竟Redis不论是在面试还是实际应用中都是极其重要的,在面试中诸如Redis的缓存问题、热key、大key、过期策略、持久化机制等;还有在实际应用中的Redis缓存、分布式锁、Reids实现排行榜、分布式限流功能、Redis做延迟队列、消息队列、发布订阅等。相信大家对这并不陌生,而作者想要做的就是在其基础上,把它们进行总结、整理、扩展并深入

一、为什么要学Redis?

目前大多数系统都是集群部署,那么在用传统的锁和缓存时就会出现以下问题:

  • 缓存失效:在分布式集群中,每个节点之间的数据不是共享的,而本地缓存是本地的,因此,在一个节点上的本地缓存可能会缓存旧数据,而在另一个节点上的数据已经更新。这就会导致数据不一致性问题,从而影响系统的正确性。
  • 互斥锁问题:传统的锁(Synchronized、Lock)是基于但服务实现的,多个服务之间无法共享锁的状态,简单来说就是锁失效,那么也会出现数据不一致等问题。

可以通过Redis的分布式缓存和分布式锁来解决上述问题。

还有就是有的功能使用关系型数据库来解决可能很复杂,而用Redis这种非关系型数据库实现就比较简单,比如聊天室功能:

  • 如果用关系型数据库,一般都需要使用JOIN来进行多表查询,而在线的聊天室通常是非常频繁的读写操作,JOIN多表查询再加上频繁读写,不仅实现起来比较复杂,性能也很差。
  • 如果用Redis,那就可以非常容易实现而且性能也远超关系型数据库。比如用Redis的List或Hash数据结构,将聊天室中的所有消息按照时间戳存储在一个列表中,用户发送的消息可以通过Redis的集合或队列存储,再使用Redis的发布订阅功能就可以实现消息的广播和接收。

二、什么是Redis?

Redis(Remote Dictionary Server),即远程字段服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

当时,Redis的作者——Antirez在工作中遇到了一个实时统计在线游戏数据的需求,起初他用Mysql数据库来解决,然而在高并发下,实时统计功能在性能上表现很差。于是在2009年开始了Redis的开发工作,之后便有了这个功能强大、高性能、可扩展、易于使用的存储系统。

ps:这就是大佬思维,我们再遇到问题时第一想法是网上搜,而大佬的思维是自己开发一个,膜拜🤗。

  • Redis最重要的功能是做缓存,查询效率远高于Mysql数据库。
  • Redis是基于内存存储数据的,读写性能贼高。
  • Redis 4.0之前,读的速度是110000次/S,写的速度是81000次/S;Redis6.0引入多线程后性能几乎翻倍,读的速度可达200000次/s,写的速度可达170000次/S。
  • Redis不仅仅是Key-Value存储结构,针对Value还有多种数据结构。
  • Redis也提供了相应的持久化方案(RDB、AOF)。
  • Redis提供了主从复制、哨兵模式和Cluster等方案实现高可用。
  • Redis提供了强大的功能,比如事务、发布订阅、Lua脚本等。

优点还有很多,不一一列举了....

Reids是一种非关系型数据库(NoSql),此外,常见的还有以下几种:

  • key-value存储:将数据以键值对的形式存储,常用于缓存,比如Reids、MemCache等。
  • 文档型存储:以类似于JSON或XML格式的文档形式存储,适用于存储和查询复杂的、半结构化的数据,比如Elasticsearch、MongDB等。
  • 面向列存储:将数据按列存储,而不是按行,适用于大规模数据处理和分析,比如HBase、Apache Cassandra等。
  • 图形化存储:以图的形式存储数据,适用于需要处理复杂关系和图算法的常见,比如Neo4j、OrientDB等。

三、Redis为什么要自己定义SDS?

从这开始就正式介绍Redis了。我们知道Redis是C语言实现的,但他并没有直接使用C语言中的字符数组的方式来实现字符串,而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS),并将SDS用作Redis的默认字符串表示,这是为什么呢?

我们先回顾下C语言中字符串的实现。C语言使用长度N+1的字符串数组来表示长度未N的字符串,并且字符串数组的最后一个元素总是为空字符'\0'

那么这就会产生两个问题:

  • 首先它就不能保存任意内容了,至少'\0'就不能保存了,因为遇到它时就直接截断了。
  • 其次就是C语言中用'\0'来表示字符串结束的方式,所以计算长度、字符串追加等操作,都需要从头遍历,直到遇到'\0'才会返回长度或追加,那么它的性能就不是很高了。

因此,Redis自己定义了一个SDS来解决以上两个问题:

  • 在用字符串数据表示字符串的同时,在这个字符串中增加一个表示分配给该字符串数组的总长度alloc字段和一个表示字符串现有长度len字段,这样在获取长度的时候就不依赖于'\0'了,直接返回len就行了。
  • 在字符串做追加操作时,只需要判断新追加的部分的len加上已有的len是否大于alloc,如果超过就重新申请新空间,反之直接追加就行了。

ps:此外,SDS还被用作缓冲区(buffer):AOF模块中的AOF缓冲区,客户端状态中的输入缓冲区。

四、Redis的数据类型与数据结构

我们常见的数据类型比如string、hash、list、set、zset等类型其实在Redis中是一个个对象,是由简单动态字符串(SDS)、哈希表、整数集合、压缩列表、跳跃表等数据结构实现的。

Reids中的每个对象都由一个redisObject结构表示,该结构中和保存数据有关的有三个属性:

  • type:记录对象的类型,比如字符串对象(string)、列表对象(list)等,可用type key命令查看value的存储类型。
  • encoding:记录对象使用的编码,比如int、embstr等(下面会提到)。
  • ptr:ptr指针指向对象底层实现数据结构,这些结构则是由encoding决定的。

对应关系如下(不是很全但够用):

上图为Redis常用的5种基本类型及Reids 5.0版本的stream类型和Redis的9种编码方式和7种底层数据结构对应的关系。下面我们详细的介绍下。

五、九种数据类型

5.1 String类型

5.1.1 简介

String类型是Redis最基本的数据类型,它可以存储任意类型的数据,比如数字、文本或者是序列化后的对象,最大可存储512MB的数据。

底层实现是SDS,由长度、空闲空间和字节数组三部分组成,并且有3种编码方式:

  • int编码:用于存储整型数据,是以Long类型存储,未使用SDS类型。

  • embstr编码:当存储的字符串长度小于等于32字节,用embstr编码。

  •  raw编码:当存储的字符串长度大于32字节,用raw编码。

5.1.2 应用场景

应用场景还是非常广泛的,比如:

  • 缓存:提高性能,降低数据库压力。
  • 计数器:利用incr和decr命令实现原子性加减操作。
  • 分布式锁:利用setnx命令。
  • 限流:利用计数器的功能来实现限流。

5.1.3 常用命令

  • SET key value:设置指定 key 的值为指定的 value。
  • GET key:获取指定 key 的值。
  • INCR key:将指定 key 的值加 1,并返回加 1 后的值。
  • DECR key:将指定 key 的值减 1,并返回减 1 后的值。
  • APPEND key value:将指定 key 的值追加指定的 value。
  • STRLEN key:返回指定 key 的值长度。
  • SETEX key seconds value:设置指定 key 的值,并指定过期时间,单位为秒。

5.2 hash类型

5.2.1 简介

hash是一个键值对集合,可以存储多个字段和值,简单的说它的value就是一个Map集合,一个hash最多可以存储2^32-1个字段。

底层实现其实有三种:

  • ziplist:压缩列表,当ziplist元素超过512个单个元素超过64字节(可在redis的配置文件中设置),会转为hashtable。

  • listpack:紧凑列表,在Redis7.0之后,listpack取代ziplist,同样,到达上述阈值会转化为hashtable。

  • hashtable:哈希表,类似map。

下面我们来看下它们编码转换的情况:

5.2.2 应用场景

  • 存储对象或实体属性:比如用户信息、商品信息。

  • 存储配置信息:比如连接字符串、端口号、默认配置等。

5.2.3 常用命令

  • HSET:设置 hash 中的字段和值。用法:HSET key field value
  • HGET:获取指定 hash 字段的值。用法:HGET key field
  • HMSET:同时设置 hash 中多个字段和值。用法:HMSET key field1 value1 [field2 value2 …]
  • HMGET:获取指定 hash 中多个字段的值。用法:HMGET key field1 [field2 …]
  • HGETALL:获取 hash 中所有字段和值。用法:HGETALL key
  • HDEL:删除 hash 中的一个或多个字段。用法:HDEL key field1 [field2 …]
  • HEXISTS:检查指定的字段在 hash 中是否存在。用法:HEXISTS key field
  • HINCRBY:将 hash 中指定字段的值增加指定增量。用法:HINCRBY key field increment
  • HINCRBYFLOAT:将 hash 中指定字段的浮点数值增加指定增量。用法:HINCRBYFLOAT key field increment
  • HKEYS:获取 hash 中所有的字段。用法:HKEYS key
  • HVALS:获取 hash 中所有的值。用法:HVALS key
  • HLEN:获取 hash 中的字段数量。用法:HLEN key
  • HSCAN:迭代遍历 hash 中的字段和值。用法:HSCAN key cursor [MATCH pattern] [COUNT count]

5.3 List类型

5.3.1 简介

List是一个存取有序的字符串列表,按照插入顺序排序,有下标,并且支持两端插入或删除元素。一个list的键最多可以存储2^32-1个元素。

底层实现是linkedlist和zipList:

  • ziplist:当ziplist的结点超过512个或节点内存大于64字节时会转为linkedlist,当然,这个在Redis配置文件中也可以修改。
  • linkedlist:双端链表。

下面介绍一下,不同版本的Redis其list的实现:

  • Reids3.2之前:list使用linkedlist和ziplist。
  • Reids3.2至Redis7.0:list使用的是quicklist,linkedlist和ziplist的结合。
  • Reids7.0之后:list使用的也是quicklist,不过将ziplist转为listpack,其实就是listpack和linkedlist结合。

5.3.2 应用场景

  • 消息队列:将消息以先后顺序添加到list中,然后可以用lpop命令从列表的左侧弹出消息并处理。
  • 实时排行榜:将用户的得分或其它评价指标作为list的值,在该指标上进行排序。通过lpush、rpush和ltrim命令可以动态地更新排行榜。
  • 发布/订阅:发布者使用rpush命令将消息推送到列表中,订阅者用blpop或brpop命令在列表上进行阻塞弹出接收消息。
  • 历史记录:将聊天记录、日志信息等存储为list的值,使用lpush和lrange命令可以存储和查询最近的几条消息。

5.3.3 常用命令

  • LPUSH:从列表的左侧添加一个或多个元素。用法:LPUSH key value1 [value2 …]
  • RPUSH:从列表的右侧添加一个或多个元素。用法:RPUSH key value1 [value2 …]
  • LPOP:从列表的左侧弹出第一个元素。用法:LPOP key
  • RPOP:从列表的右侧弹出最后一个元素。用法:RPOP key
  • LRANGE:获取列表中指定范围的元素。用法:LRANGE key start stop
  • LINDEX:获取列表中指定索引位置的元素。用法:LINDEX key index
  • LLEN:获取列表的长度(即元素数量)。用法:LLEN key
  • LTRIM:修剪列表,只保留指定范围内的元素,其余元素删除。用法:LTRIM key start stop
  • LINSERT:在列表中指定元素的前面或后面插入一个新元素。用法:LINSERT key BEFORE|AFTER pivot value
  • LREM:从列表中删除指定数量的匹配元素。用法:LREM key count value

5.4 set类型

5.4.1 简介

set是一个无序的字符串集合,不允许重复,没有下标,一个set类型的键最多可以存储2^32-1个元素。

底层实现为intset和hashtable:

  • intset:当使用intset进行存储时,redis会自动的进行递增排序,因此,只存整型的话,其是一个有顺序的结构,但是并非只存整型数据就一直用intset,当整型的元素个数超过512个元素时,会转为hashtable。当存的是非整形时,也会转为hashtable进行存储。

  • hashtable:与hash类型的哈希表相同,将元素存储在一个数组中,并通过哈希函数计算元素在数组中的索引。

5.4.2 应用场景

  • 去重:利用sadd和scard命令实现元素的去重并计数。
  • 粉丝和关注系统:使用两个set分别存储用户的关注者和粉丝,使用sadd命令和srem命令来添加和移除关注,使用sinter和sunion命令可以计算共同关注和推荐关注。
  • 抽奖:将用户存储在set中,使用sadd和srem命令增加和删除参与资格,通过srandmember命令从set中随机选择一个或多个参与者。

5.4.3 常用命令

  • SADD:向 set 中添加一个或多个元素。用法:SADD key member1 [member2 …]
  • SREM:从 set 中删除一个或多个元素。用法:SREM key member1 [member2 …]
  • SMEMBERS:获取 set 中的所有元素。用法:SMEMBERS key
  • SISMEMBER:检查元素是否在 set 中。用法:SISMEMBER key member
  • SUNION:获取多个 set 的并集。用法:SUNION key1 [key2 …]
  • SINTER:获取多个 set 的交集。用法:SINTER key1 [key2 …]
  • SDIFF:获取两个 set 的差集(第一个 set 中有,第二个 set 中没有的元素)。用法:SDIFF key1 key2
  • SCARD:获取 set 的元素数量(即集合的基数)。用法:SCARD key
  • SPOP:从 set 中随机弹出一个元素。用法:SPOP key
  • SRANDMEMBER:从 set 中随机获取一个或多个元素。用法:SRANDMEMBER key [count]

5.5 zset类型

5.5.1 简介

zset数据类型存取有序、不允许重复、有下标,并且给每个元素赋予了一个排序权重值(score)。Redis通过权重值来给集合中的元素进行从小到大排序,权重值可以重复。一个zset类型的键最多可以存储2^32-1个元素。

其底层存储结构也用了两种,ziplist和skiplist,也有切换关系:

  • ziplist:ziplist存储元素超过128个内存超过64字节,会转为skiplist。redis7.0之前是ziplist,之后为listpack。
  • skiplist:跳跃表(之后详解)。

ps:这让我想起了之前面试官问zset类型底层是什么,当时大言不惭的说跳跃表的场景😅(当时对此深信不疑)。

5.5.2 应用场景

  • 排行榜:将用户的得分、浏览量、商品销量等排序信息存储在有序集合中,使用zadd命令添加元素,使用zrange或zrevrange命令获取排行榜的前几名或全部成员,使用zrank或zrevrank命令获取指定成员在排行榜中的排名。
  • 延迟队列:将任务及其执行时间存储在 zset 中,使用任务执行时间作为元素的分值,可以使用 zadd 命令添加任务和执行时间,使用 zrange 和 zrem 命令按执行时间获取任务。
  • 区间查询:通过 zrangebyscore 或者 zrevrangebyscore 命令根据分值范围获取元素。

5.5.3 常用命令

  • ZADD:向 zset 中添加一个或多个元素,以及它们的分值。用法:ZADD key score1 member1 [score2 member2 …]
  • ZREM:从 zset 中删除一个或多个元素。用法:ZREM key member1 [member2 …]
  • ZSCORE:获取指定元素的分值。用法:ZSCORE key member
  • ZRANK:获取指定元素在 zset 中的排名(按升序)。用法:ZRANK key member
  • ZREVRANK:获取指定元素在 zset 中的倒序排名(按降序)。用法:ZREVRANK key member
  • ZRANGE:按升序获取 zset 中的一定范围元素。用法:ZRANGE key start stop [WITHSCORES]
  • ZREVRANGE:按降序获取 zset 中的一定范围元素。用法:ZREVRANGE key start stop [WITHSCORES]
  • ZCOUNT:统计 zset 中指定分值范围内的元素数量。用法:ZCOUNT key min max
  • ZINCRBY:增减指定元素的分值。用法:ZINCRBY key increment member
  • ZCARD:获取 zset 中元素的数量(即集合的基数)。用法:ZCARD key

5.6 stream类型

5.6.1 简介

stream是Redis5.0新加的一个数据类型,通常被视为一个日志或消息队列,它是一个由多个键值对组成的可持久化、有序、可重复的数据流。一个stream类型的键最多可以存储2^64-1个键值对。

底层实现是rax tree(基数树)和listpack,rax是一种压缩的前缀树结构,消息ID是作为rax中的key,消息具体数据是使用listpack保存,并作为value和消息ID一起保存到rax tree中。

5.6.2 应用场景

  • 消息队列:生产者可以使用XADD命令将消息添加到stream中,消费者可以使用XREAD或XREADGROUP命令消费消息。
  • 实时日志:每个日志视为一个消息,可以根据时间戳、唯一的消息ID、消息内容等属性进行查询和筛选。通过XADD命令添加日志,XREAD或XREADGROUP命令获取日志。
  • 事件流处理:例如用户活动流、系统监控事件等。事件流中的每个事件被视为一个消息,可以根据事件类型、时间戳、事件属性等条件进行查询和分析。

5.6.3 常用命令

  • XADD:向 Stream 中添加一条消息。用法:XADD key [MAXLEN [~|~count] [LIMIT count]] * field1 value1 [field2 value2 …] 示例:XADD mystream * name Alice age 25
  • XLEN:获取 Stream 中的消息数量。用法:XLEN key 示例:XLEN mystream
  • XRANGE:按照 ID 范围获取 Stream 中的消息列表。用法:XRANGE key start end [COUNT count] 示例:XRANGE mystream 0-0 10
  • XREAD:读取 Stream 中的消息。用法:XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key …] id [id …] 示例:XREAD COUNT 10 STREAMS mystream 0
  • XDEL:删除 Stream 中的消息。用法:XDEL key id [id …] 示例:XDEL mystream 1578854095166-0 1578854095166-1
  • XGROUP CREATE:创建消费者组。用法:XGROUP CREATE key groupname id_or_$ [MKSTREAM] 示例:XGROUP CREATE mystream mygroup $
  • XGROUP SETID:设置消费者组的消费位置。用法:XGROUP SETID key groupname id_or_$ 示例:XGROUP SETID mystream mygroup 0-0
  • XREADGROUP:消费者组读取 Stream 中的消息。用法:XREADGROUP GROUP groupname consumerkey [COUNT count] [BLOCK milliseconds] STREAMS key [key …] id [id …] 示例:XREADGROUP GROUP mygroup consumer1 COUNT 10 STREAMS mystream >
  • XACK:消费者确认已消费的消息。用法:XACK key groupname id [id …] 示例:XACK mystream mygroup 1578854095166-0 1578854095166-1
  • XCLAIM:消费者从待处理列表中获取消息。用法:XCLAIM key groupname consumer min-idle-time ID [ID …] [IDLE ms] [TIME ms-unix-time] [RETRYCOUNT count] [FORCE] 示例:XCLAIM mystream mygroup consumer1 60000 1578854095166-0

5.7 Hyperloglog类型

5.7.1 简介

Hyperloglog是一种概率数据结构,算法的最本源则是伯努利过程。用在恒定的内存大小下估计集合的计数(不同元素的个数),以及对多个集合进行并、交运算等。优点是可以使用极少的内存空间,同时可以保证较高的准确性。每个Hyperloglog键秩序要花费12KB内存,便可计算接近2^64个不同元素的基数。

底层实现是HLL_DENSE(稠密矩阵)和HLL_SPARSE(稀疏矩阵):

  • 稀疏矩阵:计数较少时使用。

  • 稠密矩阵:计数增多,超过阈值后,会转为稠密矩阵。

5.7.2 应用场景

  • 计算网站的UV(unique visitor)数量:通过记录用户请求的 IP 地址(或浏览器 cookie 等标识符),使用 HyperLogLog 可以快速估计出网站的独立访客数。
  • 统计在线用户数量:通过记录用户登录名、客户端ID等信息,使用 HyperLogLog 可以快速估计在一段时间内在线用户的数量。
  • 统计数据库中某字段的不同取值数量:通过记录字段值,使用 HyperLogLog 可以估算不同取值的数量,例如估算某个表中年龄、地区等字段的不同取值数量。

5.7.3 常用命令

  • PFADD:向 HyperLogLog 中添加一个或多个元素。用法:PFADD key element [element …] 示例:PFADD myloglog user1 user2 user3
  • PFCOUNT:获取 HyperLogLog 的基数估计值。用法:PFCOUNT key [key …] 示例:PFCOUNT myloglog
  • PFMERGE:将多个 HyperLogLog 合并为一个。用法:PFMERGE destkey sourcekey [sourcekey …] 示例:PFMERGE mergedloglog myloglog1 myloglog2
  • PEXPIRE:设置 HyperLogLog 的过期时间。用法:PEXPIRE key milliseconds 示例:PEXPIRE myloglog 60000
  • PTTL:获取 HyperLogLog 的剩余过期时间。用法:PTTL key 示例:PTTL myloglog
  • PERSIST:移除 HyperLogLog 的过期时间。用法:PERSIST key 示例:PERSIST myloglog

5.8 GEO类型

5.8.1 简介

GEO(地理位置)是一个键值对集合,其中每个元素都包含一个经度和纬度,可以用于存储地理位置信息并支持基于位置的搜索。

它是基于zset数据类型实现的,利用geohash算法将经纬度编码为二进制字符串,并作为zset的score值。在使用GEORADIUS和GEORADIUSBYMEMBER命令搜索元素时,Redis会构建一个跳跃表,以实现高效的搜索。

5.8.2 应用场景

  • 附近的人/商家搜索:通过将用户/商家的地理位置坐标存储在 Redis 的 GEO 数据结构中,可以根据用户当前的地理位置快速查询附近的人或商家,实现定位服务和位置搜索功能。
  • 地点推荐:通过存储地点的坐标和属性,可以根据用户当前的地理位置快速推荐附近的景点、餐厅、酒店等地点,并按距离排序。
  • 打车/配送系统:可以使用 GEO 数据类型来存储司机的位置和乘客的位置,以便快速匹配附近的司机和乘客,并计算两者之间的距离。
  • 热点地理位置统计:通过记录用户地理位置的访问次数,可以统计热门地点,用于展示热门景点、餐厅等信息。

5.8.3 常用命令

  • PFADD:向 HyperLogLog 中添加元素。用法:PFADD key element [element …] 示例:PFADD myloglog a b c
  • PFCOUNT:获取 HyperLogLog 的近似基数(唯一元素数量)。用法:PFCOUNT key [key …] 示例:PFCOUNT myloglog
  • PFMERGE:将多个 HyperLogLog 合并为一个 HyperLogLog。用法:PFMERGE destkey sourcekey [sourcekey …] 示例:PFMERGE merged myloglog1 myloglog2 myloglog3
  • PEXPIRE:设置 HyperLogLog 的过期时间。用法:PEXPIRE key milliseconds 示例:PEXPIRE myloglog 60000
  • PTTL:获取 HyperLogLog 的剩余过期时间。用法:PTTL key 示例:PTTL myloglog
  • PERSIST:移除 HyperLogLog 的过期时间。用法:PERSIST key 示例:PERSIST myloglog

5.9 bitmap类型

5.9.1简介

bitmap是一种紧凑的数据结构,可以用于表示一个只有0和1的数组。位图可以用于高效地存储大规模的布尔值,以及进行位运算、位图图形化等操作。一个bitmap最多可以存储2^32-1个二进制位。

底层使用了一种“压缩位图”的数据结构。通过使用两个数组来存储位图数据:一个存储实际位的值,另一个存储每个字节中1的个数。这种方式可大大压缩位图数据的大小。

5.9.2 应用场景

  • 统计在线用户:与统计用户活跃类似,可以使用 Bitmap 来实现对在线用户的统计。比如将一个 key 对应的字符串的每个比特位表示一个用户,当某个用户在线时,将对应的比特位置为 1。此时使用 BITCOUNT 命令来计算在线的用户数。
  • Bloom Filter:利用 SETBIT 和 GETBIT命令实现快速判断一个元素是否存在于一个集合中。
  • 统计用户访问情况:可以利用 Bitmap 记录用户的访问情况,如记录用户是否已浏览一篇文章。可以使用 SETBIT 命令为特定文章的每个用户设置一个比特位,并在用户浏览过该文章时,将其对应的比特位设置为 1。这些比特位的数据将存储在同一个键值下,以记住哪个用户看过哪些文章。
  • 实现位图索引:利用 bitop 和 bitpos 命令实现对多个条件进行位运算和定位

5.9.3 常用命令

  • SETBIT:设置位图在指定偏移量的值。用法:SETBIT key offset value 示例:SETBIT mybitmap 0 1
  • GETBIT:获取位图在指定偏移量的值。用法:GETBIT key offset 示例:GETBIT mybitmap 0
  • BITCOUNT:计算位图中值为1的位的数量。用法:BITCOUNT key [start end] 示例:BITCOUNT mybitmap 0 10
  • BITOP:对多个位图执行位运算操作,并将结果保存在指定位图中。用法:BITOP operation destkey key [key …] 示例:BITOP AND result mybitmap1 mybitmap2 mybitmap3
  • BITPOS:查找位图中指定bit(0或1)第一次出现的偏移量。用法:BITPOS key bit [start] [end] 示例:BITPOS mybitmap 0 100
  • BITFIELD:使用位域操作位图。用法:BITFIELD key [GET type offset] [SET type offset value] 示例:BITFIELD mybitmap GET u4 0

End:希望对大家有所帮助,如果有纰漏或者更好的想法,请您一定不要吝啬你的赐教🙋。  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/217594.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最新UI酒桌喝酒游戏小程序源码,直接上传源码到开发者端即可,带流量主

源码介绍: 2023最新UI酒桌喝酒游戏小程序源码 娱乐小程序源码 带流量主.修改增加了广告位,直接上传源码到开发者端即可。 通过后改广告代码,然后关闭广告展示提交,通过后打开即可。无广告引流。 流量主版本的(配合流…

深度解读 Cascades 查询优化器

数据库中查询优化器是数据库的核心组件,其决定着 SQL 查询的性能。Cascades 优化器是 Goetz 在 volcano optimizer generator 的基础上优化之后诞生的一个搜索框架。 本期技术贴将带大家了解 Cascades 查询优化器。首先介绍 SQL 查询优化器,接着分析查询…

CentOS 7 源码部署 Nginx

文章目录 1. 概述2. 部署示例2.1 下载和解压 Nginx 源码2.2 安装编译依赖包2.3 编译和安装2.4 启动 Nginx2.5 配置防火墙2.6 设置 Nginx 为系统服务2.7 配置访问 3. 扩展知识 1. 概述 Nginx 是一款高性能的开源 Web 服务器软件,广泛应用于互联网领域。本篇博客将介…

【日积月累】Spring中的AOP与IOC相关问题详解

Spring中的AOP与IOC 1.前言2.Spring AOP(面向切面编程)2.1 AOP的实现过程2.2 AOP代理模式的类型2.2.1JDK的动态代理2.2.2CGLIB的动态代理 2.3AOP应用常见场景2.3.1日志记录 2.4对AOP的理解 3.Spring IOC(Inversion of Control,控…

29、Windows安全配置

文章目录 一、Windows安全配置简介二、账户策略2.1 密码策略2.2 账户锁定策略 三、本地策略3.1 用户权限分配 四、安全设置4.1 账户4.2 审核4.3 设备4.4交互式登录4.5 网络访问4.6 网络安全4.7 用户账户控制4.8 防火墙配置 五、高级审核策略设置5.1 账户登录5.2 账户管理5.3 对…

架构设计系列之基础:基础理论(一)

在软件开发和软件架构领域,深厚的理论基础是构建高质量、可维护、可扩展系统的关键,本部分内容将围绕这些基础理论展开。(本部分内容介绍第一部分:编程三范式、架构设计原则、软件设计七原则) 一、编程三范式 编程范…

112. 路径总和(Java)

目录 解法: 官方解法: 方法一:广度优先搜索 思路及算法 复杂度分析 时间复杂度: 空间复杂度: 方法二:递归 思路及算法 复杂度分析 时间复杂度: 空间复杂度: 给你二叉树的…

(C++)最大连续1的个数--滑动窗口

个人主页:Lei宝啊 愿所有美好如期而遇 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://le…

MIT18.06线性代数 笔记2

文章目录 正交向量与子空间子空间投影投影矩阵和最小二乘正交矩阵和Gram-Schmidt正交化行列式及其性质行列式公式和代数余子式克拉默法则、逆矩阵、体积特征值和特征向量对角化和A的幂微分方程和exp(At)马尔科夫矩阵 傅里叶级数复习二 正交向量与子空间 向量正交:x…

【初阶C++】前言

C前言 1. 什么是C2. C发展史3. C的重要性4. 如何学习C 1. 什么是C C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, …

【Linux系统编程二十一】:(进程通信3)--消息队列/信号量(system v标准的内核数据结构的设计模式)

【Linux系统编程二十】:消息队列/信号量(system v标准的内核数据结构的设计模式) 一.消息队列二.system v标准的内核数据结构的设计三.四个概念(互斥/临界)四.信号量1.多线程并发访问2.计数器3.原子的4.总结 一.消息队列 一个叫做a进程啊,一个…

如何将LLMs封装成应用并在本地运行

最近我一直在致力于Ollama的工作,因此我花了很多时间思考如何在本地系统上运行大型语言模型(LLMs)以及如何将它们打包成应用程序。对于使用LLMs的大多数桌面应用程序而言,通常的体验要么是插入OpenAI API密钥,要么是从…

protobuf基础学习

部分内容出自:https://blog.csdn.net/baidu_32237719/article/details/99723353 proto文件来预先定义的消息格式。数据包是按照proto文件所定义的消息格式完成二进制码流的编码和解码。proto文件,简单地说,就是一个消息的协议文件&#xff0c…

MAC IDEA Maven Springboot

在mac中,使用idea进行maven项目构建 环境配置如何运行maven项目1.直接在IDEA中运行2.使用jar打包后执行 如何搭建spring boot1.添加依赖2.创建入口类3.创建控制器4. 运行5.其他 环境配置 官网安装IDEA使用IDEA的创建新项目选择创建MAEVEN项目测试IDEA的MAVEN路径是…

【二分查找】【双指针】LeetCode:2565最少得分子序列

作者推荐 【动态规划】【广度优先】LeetCode2258:逃离火灾 本文涉及的基础知识点 二分查找算法合集 有序向量的二分查找,初始化完成后,向量不会修改。 双指针: 用于计算子字符串是s的字符串的子系列。 题目 给你两个字符串 s 和 t 。 你…

《地理信息系统原理》笔记/期末复习资料(10. 空间数据挖掘与空间决策支持系统)

目录 10. 空间数据挖掘与空间决策支持系统 10.1. 空间数据挖掘 10.1.1. 空间数据挖掘的概念 10.1.2. 空间数据挖掘的方法与过程 10.1.3. 空间数据挖掘的应用 10.2. 空间决策支持系统 10.2.1. 空间决策支持系统的概念 10.2.2. 空间决策支持系统的结构 10.2.3. 空间决策…

基于chaos混沌的彩色图像加解密系统matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 混沌理论简介 4.2 基于混沌的图像加密原理 4.3 数学公式与实现过程 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .................…

记录将C语言编写的Windows程序转换为python语言编写,演示具体效果在最后,这对初学者理解Windows消息机制及框架有一定参考作用

主要思路 由于C语言的数组定义使用名字加中括号及括号内数字定义,但是在python中【】已经被作为列表 元组等序列类型分片、存取元素,因此我们不能像C语言那样定义数组 例如C语言 int a[10] 是声明定义一个含有10个int类型的数组a,而在执行语句部分…

华为OD机试真题B卷 Java 实现【统计大写字母个数】,附详细解题思路

一、题目描述 找出给定字符串中大写字符(即’A’-‘Z’)的个数。 数据范围:字符串长度:1≤∣s∣≤250 字符串中可能包含空格或其他字符 二、输入描述 对于每组样例,输入一行,代表待统计的字符串。 三、输出描述 输出一个整…

【css】css实现文字两端对齐效果:

文章目录 一、方法1:二、方法2:三、注意: 一、方法1: 给元素设置 text-align: justify;text-align-last: justify;并且加上text-justify: distribute-all-line; 目的是兼容ie浏览器 p{width: 130px;text-align: justify;text-alig…