Redis 的使⽤和原理

打印 上一主题 下一主题

主题 893|帖子 893|积分 2679

第一章:初识 Redis


1.1盛赞 Redis

   Redis   是⼀种基于键值对(key-value)的 NoSQL 数据库,与许多键值对数据库不同的是,Redis     中的值可以是由 string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、 Bitmaps(位图)、HyperLogLog、GEO(地理信息定位)等多种数据结构和算法组成,因此 Redis可以满⾜许多的应⽤场景,⽽且因为 Redis 会将所有数据都存放再内存中,所以它的读写性能⾮常惊⼈。不仅云云,Redis 还可以将内存的数据利⽤快照和⽇志的形式生存到硬盘上,如许在发⽣雷同断电或者呆板故障的时候,内存中的数据不会“丢失”。除了上述功能以外,Redis 还提供了键逾期、发布订阅、事件、流⽔线、Lua 脚本等附加功能。总之,如果在合适的场景使⽤号 Redis,它就会像⼀把瑞⼠军⼑⼀样势如破竹。     2008 年,Redis 的作者   Salvatore Sanfilippo   在开发⼀个叫 LLOOGG 的⽹站时,须要实现⼀个⾼     性能的队列功能,最开始是使⽤ MySQL 来实现的,但厥后发现⽆论怎么优化 SQL 语句等都不能使⽹站的性能提⾼上去,再加上⾃⼰囊中羞涩,于是他决定⾃⼰做⼀个专属于 LLOOGG 的数据库,这个就是 Redis 的前⾝。厥后,Salvatore Sanfilippo 将 Redis 1.0 的源码发布到   Github   上,大概连他⾃⼰都没想到,Redis 厥后云云受接待。     如果现在有⼈问 Redis 的作者都有谁在使⽤ Redis,我想他可以开句玩笑的答复:还有谁不使⽤     Redis,当然这只是开玩笑,但是从 Redis 的官⽅公司统计来看,有许多重量级的公司都在使⽤     Redis,如国外的 Twitter、Instagram、Stack Overflow、Github 等,国内就更多了,如果单单从体量来统计,新浪微博可以说是环球最⼤的 Redis 使⽤者,除了新浪微博,还有像阿⾥巴巴、腾讯、搜狐、优酷⼟⾖、美团、⼩⽶、唯品会等公司都是 Redis 的使⽤者。除此之外,许多开源技术像 ELK 等     已经把 Redis 作为它们组件中的紧张⼀环,⽽且 Redis 还提供了模块系统让第三⽅⼈员实现功能扩展,让 Redis 发挥出更⼤的威⼒。所以,可以这么说,纯熟使⽤和运维 Redis 已经成为开发运维⼈员的⼀个必备技能。    1.2 Redis 特性

     Redis 之所以受到云云多公司的⻘睐,必然有之过⼈之处,下⾯是关于 Redis 的 8 个紧张特性。       1. 速率快

       正常环境下,Redis 执⾏下令的速率⾮常快,官⽅给出的数字是读写性能可以到达 10 万 / 秒,当           然这也取决于呆板的性能,但这⾥先不讨论呆板性能上的差异,只分析⼀下是什么作育了 Redis 云云之快,可以⼤概归纳为以下四点:           •     Redis 的所有数据都是存放在内存中的,下表是⾕歌公司 2009 年给出的各层级硬件执⾏速率,所以把数据放在内存中是 Redis 速率快的最主要原因。           
          2. 基于键值对的数据结构服务器

         ⼏乎所有的编程语⾔都提供了雷同字典的功能,比方 C++ ⾥的 map、Java ⾥的 map、Python ⾥              的 dict 等,雷同于这种构造数据的⽅式叫做基于键值对的⽅式,与许多键值对数据库不同的是,              Redis 中的值不仅可以是字符串,⽽且还可以是具体的数据结构,如许不仅能便于在许多应⽤场景的开发,同时也能提⾼开发效率。Redis 的全程是 REmote Dictionary Server,它主要提供了 5 种数据结构:字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(ordered set / zset),同时在字符串的底子之上演变出了位图(Bitmaps)和 HyperLogLog 两种神奇的 ”数据结构“,而且随着 LBS(Location Based Service,基于位置服务)的不断发展,Redis 3.2. 版本种加⼊有关 GEO(地理信息定位)的功能,总之在这些数据结构的帮助下,开发者可以开发出各种 “有意思” 的应⽤。              3. 丰富的功能

           除了 5 种数据结构,Redis 还提供了许多额外的功能:                 •       提供了键逾期功能,可以⽤来实现缓存。                 •       提供了发布订阅功能,可以⽤来实现消息系统。                 •       ⽀持 Lua 脚本功能,可以利⽤ Lua 创造出新的 Redis 下令。                 •       提供了简单的事件功能,能在⼀定程度上保证事件特性。                 •       提供了流⽔线(Pipeline)功能,如许客⼾端能将⼀批下令⼀次性传到 Redis,减少了⽹络的开                 销。                4. 简单稳固

             Redis 的简单主要表现在三个⽅⾯。⾸先,Redis 的源码很少,早期版本的代码只有 2 万⾏左右,                    3.0 版本以后由于添加了集群特性,代码增⾄ 5 万⾏左右,相对于许多 NoSQL 数据库来说代码量相对要少许多,也就意味着普通的开发和运维⼈员完全可以 “吃透” 它。其次,       Redis 使⽤单线程模型       , 如许不仅使得 Redis 服务端处置惩罚模型变得简单,⽽且也使得客⼾端开发变得简单。末了,Redis 不须要依靠于操作系统中的类库(比方 Memcache 须要依靠 libevent 如许的系统类库),Redis ⾃⼰实现了事件处置惩罚的相关功能。                    但与简单相对的是 Redis 具备相当的稳固性,在⼤量使⽤过程中,很少出现因为 Redis ⾃⾝ BUG                    ⽽导致宕掉的环境。                   5. 客⼾端语⾔多

               Redis 提供了简单的 TCP 通信协议,许多编程语⾔可以很⽅便地接⼊到 Redis,而且由于 Redis 受到社区和各⼤公司的⼴泛承认,所以⽀持 Redis 的客⼾端语⾔也⾮常多,⼏乎涵盖了主流的编程语⾔,比方 C、C++、Java、PHP、Python、NodeJS 等,后续我们会对 Redis 的客⼾端使⽤做具体阐明。                      6. 持久化(Persistence)

                 通常看,将数据放在内存中是不安全的,⼀旦发⽣断电或者呆板故障,紧张的数据大概就会丢                          失,因此 Redis 提供了两种持久化⽅式:RDB 和 AOF,即可以⽤两种策略将内存的数据生存到硬盘中                          (如图 1-1 所⽰),如许就保证了数据的可持久性,后续我们将对 Redis 的持久化进⾏具体阐明。                          
                         7. 主从复制(Replication)

                   Redis 提供了复制功能,实现了多个相同数据的 Redis 副本(Replica)(如图 1- 2 所⽰),复制                             功能是分布式 Redis 的底子。后续我们会对 Redis 的复制功能进⾏具体演⽰。                           
                            8. ⾼可⽤(High Availability)和分布式(Distributed)

                     Redis 提供了⾼可⽤实现的 Redis 哨兵(Redis Sentinel),可以或许保证 Redis 结点的故障发现和故                                障⾃动转移。也提供了 Redis 集群(Redis Cluster),是真正的分布式实现,提供了⾼可⽤、读写和容量的扩展性                    1.3 Redis 使⽤场景

                     1.3.1 Redis 可以做什么

           1. 缓存(Cache)

                       缓存机制⼏乎在所有⼤型⽹站都有使⽤,合理地使⽤缓存不仅可以加速数据的访问速率,⽽且能                                   够有效地低落后端数据源的压⼒。Redis 提供了键值逾期时间设置,而且也提供了灵活控制最⼤内存和内存溢出后的淘汰策略。可以这么说,⼀个合理的缓存筹划可以或许为⼀个⽹站的稳固保驾护航。                       2. 排⾏榜系统

                       排⾏榜系统⼏乎存在于所有的⽹站,比方按照热度排名的排⾏榜,按照发布时间的排⾏榜,按照                                   各种复杂维度计算出的排⾏榜,Redis 提供了列表和有序集合的结构,合理地使⽤这些数据结构可以很⽅便地构建各种排⾏榜系统。                       3. 计数器应⽤

                       计数器在⽹站中的作⽤⾄关紧张,比方视频⽹站有播放数、电商⽹站有欣赏数,为了保证数据的                                   实时性,每⼀次播放和欣赏都要做加 1 的操作,如果并发量很⼤对于传统关系型数据的性能是⼀种挑战。Redis 自然⽀持计数功能⽽且计数的性能也⾮常好,可以说是计数器系统的紧张选择。                       4. 交际⽹络

                       赞 / 踩、粉丝、共同好友 / 喜好、推送、下拉刷新等是交际⽹站的必备功能,由于交际⽹站访问量                                   通常⽐较⼤,⽽且传统的关系型数据不太合适生存这种范例的数据,Redis 提供的数据结构可以相对⽐较容易地实现这些功能。                       5. 消息队列系统

                       消息队列系统可以说是⼀个⼤型⽹站的必备底子组件,因为其具有业务解耦、⾮实时业务削峰等                                   特性。Redis 提供了发布订阅功能和壅闭队列的功能,虽然和专业的消息队列⽐还不够⾜够强⼤,但是对于⼀般的消息队列功能根本可以满⾜                                  1.3.2 Redis 不可以做什么

                         现实上和任何⼀⻔技术⼀样,每个技术都有⾃⼰的应⽤场景和边界,也就是说 Redis 并不是万⾦                                      油,有许多合适它解决的题目,但是也有许多不合适它解决的题目。             我们可以站在数据规模和数据冷热的⻆度来进⾏分析。                                                   站在数据规模的⻆度看,数据可以分为⼤规模数据和⼩规模数据,我们知道 Redis 的数据是存放                                      在内存中的,虽然现在内存已经⾜够便宜,但是如果数据量⾮常⼤,比方每天有⼏亿的⽤⼾⾏为数                                      据,使⽤ Redis 来存储的话,根本上是个⽆底洞,经济本钱相当⾼。                                      站在数据冷热的⻆度,数据分为热数据和冷数据,热数据通常是指须要频繁操作的数据,反之为                                      冷数据             ,比方对于视频⽹站来说,视频根本信息根本上在各个业务线都是经常要操作的数据,⽽⽤⼾的观看记录不⼀定是经常须要访问的数据,这⾥临时不讨论两者数据规模的差异,单纯站在数据冷热的⻆度上看,视频信息属于热数据,⽤⼾观看记录属于冷数据。如果将这些冷数据放在 Redis 上,根本上是对于内存的⼀种浪费,但是对于⼀些热数据可以放在 Redis 中加速读写,也可以减轻后端存储的负载,可以说是事半功倍。                                      所以,Redis 并不是万⾦油,相信随着我们对 Redis 的逐步学习,可以或许清晰 Redis 真正的使⽤场                                      景。                        第⼆章 Redis 常⻅数据范例

            
            2.1.1 根本全局下令

                         Redis 有 5 种数据结构,但它们都是键值对种的值,对于键来说有⼀些通⽤的下令。                         KEYS

            

                         返回所有满⾜样式(pattern)的 key。⽀持如下统配样式。                                      •              h?llo              匹配              hello              ,              hallo              和              hxllo                                      •              h*llo              匹配              hllo              和              heeeello                                      •              h[ae]llo              匹配              hello              和              hallo              但不匹配              hillo                                      •              h[^e]llo              匹配              hallo              ,              hbllo              , ... 但不匹配              hello                                      •              h[a-b]llo              匹配              hallo              和              hbllo                                     返回值:匹配 pattern 的所有 key。                                     EXISTS

                           判定某个 key 是否存在。                                         
                                        DEL

                             删除指定的 key。                                          
                                                           返回值:删撤除的 key 的个数                                                          EXPIRE

                               为指定的 key 添加秒级的逾期时间(Time To Live TTL)                                             
                                                               返回值:1 表⽰设置成功。0 表⽰设置失败                                                              TTL

                                 获取指定 key 的逾期时间,秒级                                                
                                                                   剩余逾期时间。-1 表⽰没有关联逾期时间,-2 表⽰ key 不存在。                                                                                     关于键逾期机制,可以参考图 2-1 所⽰。                                                                  
                                                 TYPE

                                   返回 key 对应的数据范例。                                                   
                                                    返回值:                   none                   ,                   string                   ,                   list                   ,                   set                   ,                   zset                   ,                   hash                   and                   stream                                                    2.1.2 数据结构和内部编码

                                     type 下令现实返回的就是当前键的数据结构范例,它们分别是:string(字符串)、list(列                                                        表)、hash(哈希)、set(集合)、zset(有序集合),但这些只是 Redis 对外的数据结构。                                                       Redis 的 5 种数据范例                                                        
                                                                           现实上 Redis 针对每种数据结构都有⾃⼰的底层内部编码实现,⽽且是多种实现,如许 Redis 会                                                           在合适的场景选择合适的内部编码,如表 2-1 所⽰。                                                         
                                                                               可以看到每种数据结构都有⾄少两种以上的内部编码实现,比方 list 数据结构包含了 linkedlist 和                                                              ziplist 两种内部编码。同时有些内部编码,比方 ziplist,可以作为多种数据结构的内部实现,可以通过 object encoding 下令查询内部编码                                                                                   可以看到 hello 对应值的内部编码是 embstr,键 mylist 对应值的内部编码是 ziplist。                                                                 Redis 如许筹划有两个好处:                                                                 1)可以改进内部编码,⽽对外的数据结构和下令没有任何影响,如许⼀旦开发出更优秀的内部编码,⽆需改动外部数据结构和下令,比方 Redis 3.2 提供了 quicklist,联合了 ziplist 和 linkedlist 两者的优势,为列表范例提供了⼀种更为优秀的内部编码实现,⽽对⽤⼾来说根本⽆感知。                                                                 2)多种内部编码实现可以在不同场景下发挥各⾃的优势,比方 ziplist ⽐较节省内存,但是在列表元素⽐较多的环境下,性能会降落,这时候 Redis 会根据设置选项将列表范例的内部实现转换为                                                                 linkedlist,整个过程⽤⼾同样⽆感知。                                          2.1.3 单线程架构

                                                                  Redis 使⽤了单线程架构来实现⾼性能的内存数据库服务,本节⾸先通过多个客⼾端下令调⽤的例                                                                    ⼦阐明 Redis 单线程下令处置惩罚机制,接着分析 Redis 单线程模型为什么性能云云之⾼,最终给出为什么明白单线程模型是使⽤和运维 Redis 的关键。                                             1. 引出单线程模型

                      redis单线程,只有一个线程去吸取处置惩罚所有的请求,并不是服务器进程内部只有一个线程,其实也有许多线程,这些线程都在处置惩罚网络IO
                     

                      上面这个环境,大概会有线程安全题目
                     

                      其实redis服务器并不会有这种环境,因为redis服务器是单线程服务器,把吸取到的请求串行实行,多个请求到达redis队列中,也是须要进行列队期待的.
                      redis可以或许使用单线程模型,很好的工作,是因为redis处置惩罚的业务逻辑是短平快,不斲丧CPU资源,如果一个操作实行的时间太长,就会影响其他的请求的实行
                      2.为什么redis是单线程,速率还能这么快,效率这么高?

                      他的速率快和效率高是与关系性数据库(MySQL,Orcale)进行对比
                      1.redis直接访问的是内存,而关系性数据库访问的硬盘
                      2.redis的核心功能,比关系性数据库的核心功能要简单,数据库对于数据的插入查询,都有更复杂的功能支持,
                      3.单线程模型,减少了不须要的线程竞争开销,redis每个操作都是短平快,不涉及特别斲丧cpu的操作
                      4.处置惩罚网络IO的时候,使用了epoll如许的IO多路复用机制,IO多路复用机制,一个线程就可以处置惩罚多个socket,,epoll事件关照/回调机制,一个线程可以完成好多使命,前提是这些使命的交互不频繁,大部分时间都在等,可以采取epoll多路复用机制
                     

                      1.String 字符串

                      在redis中,所以的key都是string范例,value的数据范例才有差异
                                             字符串范例是 Redis 最底子的数据范例,直接按照二进制数据的方式进行存储,不会做任何的编码转化,存的是啥,取出来就是啥,关于字符串须要特别注意:1)⾸先 Redis 中所有的键的 范例都是字符串范例,⽽且其他⼏种数据结构也都是在字符串雷同底子上构建的,比方列表和集合的元素范例是字符串范例,所以字符串范例能为其他 4 种数据结构的学习奠定底子。2)其次,如图 2-7所⽰,字符串范例的值现实可以是字符串,包含⼀般格式的字符串或者雷同 JSON、XML 格式的字符串;数字,可以是整型或者浮点型;甚⾄是⼆进制流数据,比方图⽚、⾳频、视频等。不过⼀个字符串的最⼤值不能超过 512 MB。                                             

                      常见下令

                                            SET

                                             将 string 范例的 value 设置到 key 中。如果 key 之前存在,则覆盖,⽆论原来的数据范例是什么。之前关于此 key 的 TTL 也全部失效。                                                                    语法:                                                                    1                        SET key value [expiration EX seconds|PX milliseconds] [NX|XX]                                                                    下令有效版本:1.0.0 之后                                                                    时间复杂度:O(1)                                            

                                             SET 下令⽀持多种选项来影响它的⾏为:                                                                    •                        EX                        seconds⸺使⽤秒作为单位设置 key 的逾期时间。                                                                    •                        PX                        milliseconds                       ⸺使⽤毫秒作为单位设置 key 的逾期时间。                                                                    •                        NX                        ⸺只在 key 不存在时才进⾏设置,即如果 key 之前已经存在,设置不执⾏。                                                                    •                        XX                        ⸺只在 key 存在时才进⾏设置,即如果 key 之前不存在,设置不执⾏。                                                                                            返回值:                                                                       •                         如果设置成功,返回 OK。                                                                       •                         如果由于 SET 指定了 NX 或者 XX 但条件不满⾜,SET 不会执⾏,并返回 (nil)。                                                                       
                                                                      GET

                                                 获取 key 对应的 value。如果 key 不存在,返回 nil。如                         果 value 的数据范例不是 string,会报错                         。                                                                          语法:                                                                          1                          GET key                                                                          下令有效版本:1.0.0 之后                                                                          时间复杂度:O(1)                                                                          返回值:key 对应的 value,或者 nil 当 key 不存在。                                                                        
                                                                         MGET

                                                   ⼀次性获取多个 key 的值。如果对应的 key 不存在或者对应的数据范例不是 string,返回 nil。                                                                             语法:                                                                             1                           MGET key [key ...]                                                                             下令有效版本:1.0.0 之后                                                                             时间复杂度:O(N) N 是 key 数目                                                                             返回值:对应 value 的列表                                                                             MSET

                                                     ⼀次性设置多个 key 的值。                                                                                语法:                                                                                1                            MSET key value [key value ...]                                                                                下令有效版本:1.0.1 之后                                                                                时间复杂度:O(N) N 是 key 数目                                                                                返回值:永远是 OK                                                                              
                                                                              
                                                                              
                                                                                                           学会使⽤批量操作,可以有效提⾼业务处置惩罚效率,但是要注意,每次批量操作所发送的键的数目也不是⽆控制的,否则大概造成单⼀下令执⾏时间过⻓,导致 Redis 壅闭。                                                                                  SETNX

                                                         设置 key-value 但只答应在 key 之前不存在的环境下。                                                                                      语法:                                                                                      1                              SETNX key value                                                                                      下令有效版本:1.0.0 之后                                                                                      时间复杂度:O(1)                                                                                      返回值:1 表⽰设置成功。0 表⽰没有设置。                                                                                    
                                                                                                                   SET、SET NX、SET XX 执⾏流程                                                                                                                  
                                                                                     计数下令

                                                                                    
                                                                                     INCR

                                                           将 key 对应的 string 表⽰的数字加⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。                                                                                                                                               INCRBY

                                                           将 key 对应的 string 表⽰的数字加上对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。                                                                                        返回值:integer 范例的加完后的数值。                                                                                                                      DECR

                                                             将 key 对应的 string 表⽰的数字减⼀。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错                                                                                                                         DECYBY

                                                               将 key 对应的 string 表⽰的数字减去对应的值。如果 key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的 string 不是⼀个整型或者范围超过了 64 位有符号整型,则报错。                                                                                                                             INCRBYFLOAT

                                                                 将 key 对应的 string 表⽰的浮点数加上对应的值。如果对应的值是负数,则视为减去对应的值。如果key 不存在,则视为 key 对应的 value 是 0。如果 key 对应的不是 string,或者不是⼀个浮点数,则报错。答应采⽤科学计数法表⽰浮点数。                                                                                                                                                                    许多存储系统和编程语⾔内部使⽤ CAS 机制实现计数功能,会有⼀定的 CPU 开销,但在 Redis 中完全不存在这个题目,因为 Redis 是单线程架构,任何下令到了 Redis 服务端都要顺序执⾏。                                                                                                     
                                                                                                    APPEND

                                                                     如果 key 已经存在而且是⼀个 string,下令会将 value 追加到原有 string 的后边。如果 key 不存在,则效果等同于 SET 下令。                                                                                                        语法:                                                                                                        1                                    APPEND KEY VALUE                                                                                                                                           时间复杂度:O(1). 追加的字符串⼀般⻓度较短, 可以视为 O(1).                                                                                                           返回值:追加完成之后 string 的⻓度。                                                                                                                                                                          
                                                                  GETRANGE

                                                                   返回 key 对应的 string 的⼦串,由 start 和 end 确定(左闭右闭)。可以使⽤负数表⽰倒数。-1 代表倒数第⼀个字符,-2 代表倒数第⼆个,其他的与此雷同。超过范围的偏移量会根据 string 的⻓度调解成正确的值。                                                                                                     语法:                                                                                                     1                                   GETRANGE key start end                                                                                                     时间复杂度:O(N). N 为 [start, end] 区间的⻓度. 由于 string 通常⽐较短, 可以视为是 O(1)                                                                                                     返回值:string 范例的⼦串                                                                                                   
                                                                                                    SETRANGE

                                                                     覆盖字符串的⼀部分,从指定的偏移开始。                                                                                                        语法:                                                                                                        1                                    SETRANGE key offset value                                                                                                        时间复杂度:O(N), N 为 value 的⻓度. 由于⼀般给的 value ⽐较短, 通常视为 O(1).                                                                                                        返回值:更换后的 string 的⻓度。                                                                                                        
                                                                                                                                         STRLEN

                                                                       获取 key 对应的 string 的⻓度。当 key 存放的雷同不是 string 时,报错。                                                                                                           语法:                                                                                                           1                                     STRLEN key                                                                                                           时间复杂度:O(1)                                                                                                           返回值:string 的⻓度。或者当 key 不存在时,返回 0                                                                                                         
                                                                                                          下令⼩结

                                                                         字符串范例下令的效果、时间复杂度,可以参考此表,联合业务需求和数据⼤⼩选择合适的下令。                                                                                                                                               
                                                                                                          内部编码

                                    
                                                                         字符串范例的内部编码有 3 种:使用object encoding来查询当前编码                                                                                                             int:8 个字节的⻓整型。                                                                                                              
                                                                                                             embstr:⼩于即是 39 个字节的字符串。                                                                                                              
                                                                                                             raw:⼤于 39 个字节的字符串                                                                        

                                    

                                    

                                    典范使⽤场景

                                    
                                    缓存(Cache)功能

                                                                         图 2-10 是⽐较典范的缓存使⽤场景,此中 Redis 作为缓冲层,MySQL 作为存储层,绝⼤部分请                                                                                                              求的数据都是从 Redis 中获取。由于 Redis 具有⽀撑⾼并发的特性,所以缓存通常能起到加速读写和低落后端压⼒的作⽤。                                                                        

                                    

                                    举一个例子来明白一下缓存
                                    这是一段伪代码
                                                                         1)假设业务是根据⽤⼾ uid 获取⽤⼾信息                                                                                                              UserInfo getUserInfo(long uid) {                                                                                                              ...                                                                                                              }                                                                                                                                                   2)⾸先从 Redis 获取⽤⼾信息,我们假设⽤⼾信息生存在 "user:info:<uid>" 对应的键中:                                                                                                                 //                                       根据                                       uid                                       得到                                       Redis                                       的键                                                                                                                 String key = "user:info:" + uid;                                                                                                                 //                                       尝试从                                       Redis                                       中获取对应的值                                                                                                                 String value = Redis                                       执⾏下令:                                      get key;                                                                                                                 //                                       如果缓存掷中(                                      hit                                      )                                                                                                                 if (value != null) {                                                                                                                 //                                       假设我们的⽤⼾信息按照                                       JSON                                       格式存储                                                                                                                 UserInfo userInfo = JSON                                       反序列化                                      (value);                                                                                                                 return userInfo;                                                                                                                 }                                                                                                                                                        如果没有从 Redis 中得到⽤⼾信息,及缓存 miss,则进⼀步从 MySQL 中获取对应的信息,随后写⼊缓存并返回:                                                                                                                    //                                        如果缓存未掷中(                                       miss                                       )                                                                                                                    if (value == null) {                                                                                                                    //                                        从数据库中,根据                                        uid                                        获取⽤⼾信息                                                                                                                    UserInfo userInfo = MySQL                                        执⾏                                        SQL                                       :                                       select * from user_info where uid = <uid>                                                                                                                    //                                        如果表中没有                                        uid                                        对应的⽤⼾信息                                                                                                                    if (userInfo == null) {                                                                                                                    响应                                        404                                                                                                                    return null;                                                                                                                    }                                                                                                                    //                                        将⽤⼾信息序列化成                                        JSON                                        格式                                                                                                                    String value = JSON                                        序列化                                       (userInfo);                                                                                                                    //                                        写⼊缓存,为了防⽌数据腐烂(                                       rot                                       ),设置逾期时间为                                        1                                        ⼩时(                                       3600                                        秒)                                                                                                                    Redis                                        执⾏下令:                                       set key value ex 3600                                                                                                                    //                                        返回⽤⼾信息                                                                                                                    return userInfo;                                                                                                                    }                                                                                                                                                   redis如许的缓存,经常存储"热门"数据(被高频使用的数据),最近一段时间都会反复用到的数据,
                                    

                                    计数(Counter)功能

                                    
                                                                         许多应⽤都会使⽤ Redis 作为计数的底子⼯具,它可以实现快速计数、查询缓存的功能,同时数                                                                                                              据可以异步处置惩罚或者落地到其他数据源。如图 2-11 所⽰,比方视频⽹站的视频播放次数可以使⽤                                                                                                              Redis 来完成:⽤⼾每播放⼀次视频,相应的视频播放数就会⾃增 1。                                                                                                              
                                                                                                                                                   //                                       在                                       Redis                                       中统计某视频的播放次数                                                                                                                                                                                        long incrVideoCounter(long vid) {                                                                                                                 key = "video:" + vid;                                                                                                                 long count = Redis                                       执⾏下令:                                      incr key                                                                                                                 return count;                                                                                                                 }                                                                                                                共享会话(Session)

                                                                             如图 2-12 所⽰,⼀个分布式 Web 服务将⽤⼾的 Session 信息(比方⽤⼾登录信息)生存在各⾃                                                                                                                    的服务器中,但如许会造成⼀个题目:出于负载均衡的考虑,分布式服务会将⽤⼾的访问请求均衡到不同的服务器上,而且通常⽆法保证⽤⼾每次请求都会被均衡到同⼀台服务器上,如许当⽤⼾刷新⼀次访问是大概会发现须要重新登录,这个题目是⽤⼾⽆法容忍的。                                                                                                                    
                                                                                                                                                           为了解决这个题目,可以使⽤ Redis 将⽤⼾的 Session 信息进⾏集中管理,如图 2-13 所⽰,在这种模式下,只要保证 Redis 是⾼可⽤和可扩展性的,⽆论⽤⼾被均衡到哪台 Web 服务器上,都集中从Redis 中查询、更新 Session 信息。                                                                                                                       
                                                                                                                                                             ⼿机验证码

                                                                                 许多应⽤出于安全考虑,会在每次进⾏登录时,让⽤⼾输⼊⼿机号而且共同给⼿机发送验证码,                                                                                                                          然后让⽤⼾再次输⼊收到的验证码并进⾏验证,从⽽确定是否是⽤⼾本⼈。为了短信接⼝不会频繁访问,会限定⽤⼾每分钟获取验证码的频率,比方⼀分钟不能超过 5 次                                                                                                                        
                                                                                                                                                                   此功能可以⽤以下伪代码阐明根本实现思绪:                                                                                                                             
                                                                                                                           
                                                                                                                            2.Hash 哈希

                                                                                     ⼏乎所有的主流编程语⾔都提供了哈希(hash)范例,它们的叫法大概是哈希、字典、关联数                                                                                                                                组、映射。在 Redis 中,哈希范例是指值本⾝⼜是⼀个键值对结构,形如 key = "key",value = { {                                                                                                                                field1, value1 }, ..., {fieldN, valueN } },Redis 键值对和哈希范例⼆者的关系可以⽤图 2-15 来表⽰。                                                                                                                              
                                                                                    常见下令

                                          1.HSET

                                                                                     设置 hash 中指定的字段(field)的值(value)。                                                                                                                                语法:                                                                                                                                HSET key field value [field value ...]                                                                                                                                时间复杂度:插⼊⼀组 field 为 O(1), 插⼊ N 组 field 为 O(N)                                                                                                                                返回值:添加的字段的个数。                                                                                                                              
                                                                                                                               2.HGET

                                                                                       获取 hash 中指定字段的值。                                                                                                                                   语法:                                                                                                                                   1                                             HGET key field                                                                                                                                   时间复杂度:O(1)                                                                                                                                   返回值:字段对应的值或者 nil。                                                                                                                                 
                                                                                                                                  3.HEXISTS

                                                                                         判定 hash 中是否有指定的字段。                                                                                                                                      语法:                                                                                                                                      HEXISTS key field                                                                                                                                      时间复杂度:O(1)                                                                                                                                      返回值:1 表⽰存在,0 表⽰不存在。                                                                                                                                      
                                                                                                                                     4.HDEL

                                                                                           删除 hash 中指定的字段。                                                                                                                                         语法:                                                                                                                                         1                                               HDEL key field [field ...]                                                                                                                                         时间复杂度:删除⼀个元素为 O(1). 删除 N 个元素为 O(N).                                                                                                                                         返回值:本次操作删除的字段个数。                                                                                                                                         
                                                                                                                                        5.HKEYS

                                                                                             获取 hash 中的所有字段。                                                                                                                                            语法:                                                                                                                                            HKEYS key                                                                                                                                            时间复杂度:O(N), N 为 field 的个数.                                                                                                                                            返回值:字段列表。                                                                                                                                            
                                                                                                                                                                                           6.HVALS                                                                                                                                               获取 hash 中的所有的值。                                                                                                                                               语法:                                                                                                                                               HVALS key                                                                                                                                               时间复杂度:O(N), N 为 field 的个数.                                                                                                                                               返回值:所有的值。                                                                                                                                               
                                                                                                                                              6.HGETALL

                                                                                                 获取 hash 中的所有字段以及对应的值。                                                                                                                                                  语法:                                                                                                                                                  HGETALL key                                                                                                                                                  时间复杂度:O(N), N 为 field 的个数.                                                                                                                                                  返回值:字段和对应的值。                                                                                                                                                  
                                                                                                                                                 7.HMGET

                                                                                                   ⼀次获取 hash 中多个字段的值。                                                                                                                                                     语法:                                                                                                                                                     HMGET key field [field ...]                                                                                                                                                     时间复杂度:只查询⼀个元素为 O(1), 查询多个元素为 O(N), N 为查询元素个数.                                                                                                                                                     返回值:字段对应的值或者 nil。                                                                                                                                                     
                                                                                                                                                                                                                                                         在使⽤ HGETALL 时,如果哈希元素个数⽐较多,会存在壅闭 Redis 的大概。如果开发⼈员只                                                                                                                                                        须要获取部分 field,可以使⽤ HMGET,如果⼀定要获取全部 field,可以尝试使⽤ HSCAN                                                                                                                                                        下令,该下令采⽤渐进式遍历哈希范例,                                                                                                                                                       8.HLEN

                                                                                                       获取 hash 中的所有字段的个数。                                                                                                                                                           语法:                                                                                                                                                           HLEN key                                                                                                                                                           时间复杂度:O(1)                                                                                                                                                           返回值:字段个数。                                                                                                                                                         
                                                                                                                                                          9.HSETNX

                                                                                                         在字段不存在的环境下,设置 hash 中的字段和值。                                                                                                                                                              语法:                                                                                                                                                              HSETNX key field value                                                                                                                                                              时间复杂度:O(1)                                                                                                                                                              返回值:1 表⽰设置成功,0 表⽰失败。                                                                                                                                                            
                                                                                                                                                             10.HINCRBY

                                                                                                           将 hash 中字段对应的数值添加指定的值。                                                                                                                                                                 语法:                                                                                                                                                                 HINCRBY key field increment                                                                                                                                                                 时间复杂度:O(1)                                                                                                                                                                 返回值:该字段变化之后的值                                                                                                                                                               
                                                                                                                                                                                                                       HINCRBYFLOAT                                                                                                                                                                    HINCRBY 的浮点数版本。                                                                                                                                                                    语法:                                                                                                                                                                    HINCRBYFLOAT key field increment                                                                                                                                                                    时间复杂度:O(1)                                                                                                                                                                    返回值:该字段变化之后的值。                                                                                                                                                                  
                                                                                                                                                                   下令⼩结

                                                                                                               表 2-4 是哈希范例下令的效果、时间复杂度,开发⼈员可以参考此表,联合⾃⾝业务需求和数据                                                                                                                                                                       ⼤⼩选择合适的下令。                                                                                                                                                                     
                                                                                                                                                                     
                                                                                                                                                                     
                                                                                                                                                                      内部编码

                                                                                                                 哈希的内部编码有两种:                                                                                                                 ziplist(压缩列表):

                                                                                                                 当哈希范例元素个数⼩于 hash-max-ziplist-entries 设置(默认 512 个)、                                                                                                                                                                          同时所有值都⼩于 hash-max-ziplist-value 设置(默认 64 字节)时,Redis 会使⽤ ziplist 作为哈                                                                                                                                                                          希的内部实现,ziplist 使⽤更加紧凑的结构实现多个元素的连续存储,所以在节省内存⽅⾯⽐                                                                                                                                                                          hashtable 更加优秀。                                                                                                                 hashtable(哈希表):

                                                                                                                 当哈希范例⽆法满⾜ ziplist 的条件时,Redis 会使⽤ hashtable 作为哈希                                                                                                                                                                          的内部实现,因为此时 ziplist 的读写效率会降落,⽽ hashtable 的读写时间复杂度为 O(1)。                                                                                                                                                                          下⾯的⽰例演⽰了哈希范例的内部编码,以及响应的变化                                                                                                                                                                        
                                                                                                                                                                        
                                                                                                                                                                         1)当 field 个数⽐较少且没有⼤的 value 时,内部编码为 ziplist:
                                                         2)当有 value ⼤于 64 字节时,内部编码会转换为 hashtable:
                                                         3)当 field 个数超过 512 时,内部编码也会转换为 hashtable:
                                                                                                                                                                         使⽤场景

                                                                                                                   图 2-16 为关系型数据表记录的两条⽤⼾信息,⽤⼾的属性表现为表的列,每条⽤⼾信息表现为                                                                                                                                                                             ⾏。                                                                                                                                                                           
                                                                                                                                                                            。如果映射关系表⽰这两个⽤⼾信息,则如图 2-17 所⽰。                                                                                                                                                                           
                                                                                                                                                                                                                                       相⽐于使⽤ JSON 格式的字符串缓存⽤⼾信息,哈希范例变得更加直观,而且在更新操作上变得                                                                                                                                                                                更灵活。可以将每个⽤⼾的 id 界说为键后缀,多对 field-value 对应⽤⼾的各个属性                                                                                                                    注意

                                                                                                                     哈希范例和关系型数据库有两点不同之处:                                                                                                                                                                                                                                           •                                                                                                                                                                                   哈希范例是希罕的,⽽关系型数据库是完全结构化的,比方哈希范例每个键可以有不同的 field,⽽                                                                                                                                                                                   关系型数据库⼀旦添加新的列,所有⾏都要为其设置值,即使为 null,如图 2-18 所⽰。                                                                                                                                                                                   
                                                                                                                                                                                  •                                                                                                                                                                                   关系数据库可以做复杂的关系查询,⽽ Redis 去模仿关系型复杂查询,比方联表查询、聚合查询等                                                                                                                                                                                   根本不大概,维护本钱⾼。                                                                                                                                                                                  缓存⽅式对⽐

                                                                                                                         截⾄⽬前为⽌,我们已经可以或许⽤三种⽅法缓存⽤⼾信息,下⾯给出三种⽅案的实现⽅法和优缺点                                                                                                                                                                                      分析。                                                                                                                                                                                     1. 原⽣字符串范例

                                                                                                                           使⽤字符串范例,每个属性⼀个键。                                                                                                                                                                                         set user:1:name James                                                                                                                                                                                         set user:1:age 23                                                                                                                                                                                         set user:1:city Beijing                                                                                                                                                                                                                                                        优点:实现简单,针对个别属性变更也很灵活。                                                                                                                                                                                            缺点:占⽤过多的键,内存占⽤量较⼤,同时⽤⼾信息在 Redis 中⽐较分散,缺少内聚性,所以这种⽅案根本没有实⽤性。                                                                                                                            2. 序列化字符串范例,比方 JSON 格式

                                                              
                                                                                                                             set user:1                                                                颠末序列化后的⽤⼾对象字符串                                                                                                                                                                                            优点:针对总是以团体作为操作的信息⽐较合适,编程也简单。同时,如果序列化⽅案选择合适,内存的使⽤效率很⾼。                                                                                                                                                                                            缺点:本⾝序列化和反序列须要⼀定开销,同时如果总是操作个别属性则⾮常不灵活。                                                                                                                                                                                            
                                                                                                                                                                                           3. 哈希范例         

                                                                                                                               hmset user:1 name James age 23 city Beijing                                                                                                                                                                                               优点:简单、直观、灵活。尤其是针对信息的局部变更或者获取操作。                                                                                                                                                                                               缺点:须要控制哈希在 ziplist 和 hashtable 两种内部编码的转换,大概会造成内存的较⼤斲丧。                                                                                                                              关于内聚和耦合

                                                               高内聚:有关联的代码紧密联系在一起
                                                               

                                                               低耦合:代码的各个模块之间影响不大
                                                               

                                                               3.List列表

                                                                                                                               列表范例是⽤来存储多个有序的字符串,如图 2-19 所⽰,a、b、c、d、e 五个元素从左到右组成                                                                                                                                                                                               了⼀个有序的列表,列表中的每个字符串称为元素(element),⼀个列表最多可以存储 个元                                                                                                                                                                                               素。在 Redis 中,可以对列表两端插⼊(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等(如图 2-19 和图 2-20 所⽰)。列表是⼀种⽐较灵活的数据结构,它可以充当栈和队列的⻆⾊,在现实开发上有许多应⽤场景                                                                                                                                                                                             
                                                                                                                                                                                             
                                                                                                                                                                                              列表范例的特点:

                                                                第⼀:

                                                                                                                                 列表中的元素是有序的,这意味着可以通过索引下标获取某个元素或者某个范围的元素列表,                                                                                                                                                                                                  比方要获取图 2-20 的第 5 个元素,可以执⾏ lindex user:1:messages 4 或者倒数第 1 个元素,lindex user:1:messages -1 就可以得到元素 e。                                                                                                                                 第⼆

                                                                                                                                 区分获取和删除的区别,比方图 2-20 中的 lrem 1 b 是从列表中把从左数遇到的前 1 个 b 元素删                                                                                                                                                                                                  除,这个操作会导致列表的⻓度从 5 变成 4;但是执⾏ lindex 4 只会获取元素,但列表⻓度是不会变化的。                                                                                                                                 第三

                                                                                                                                 列表中的元素是答应重复的,比方图 2-21 中的列表中是包含了两个 a 元素的。                                                                                                                                                                                                  
                                                                                                                                                                                              常见下令

                                                               LPUSH(头插)

                                                                                                                               将⼀个或者多个元素从左侧放⼊(头插)到 list 中。                                                                                                                                                                                               语法:                                                                                                                                                                                               LPUSH key element [element ...]                                                                                                                                                                                               
                                                                                                                                                                                              时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.                                                                                                                                                                                               返回值:插⼊后 list 的⻓度                                                                                                                                                                                              LPUSHX

                                                                                                                                 在 key 存在时,将⼀个或者多个元素从左侧放⼊(头插)到 list 中。不存在,直接返回0                                                                                                                                                                                                 语法:                                                                                                                                                                                                  1                                                                  LPUSHX key element [element ...]                                                                                                                                                                                                  
                                                                                                                                                                                                 时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.                                                                                                                                                                                                  返回值:插⼊后 list 的⻓度。                                                                                                                                                                                                 RPUSH(尾插)

                                                                                                                                   将⼀个或者多个元素从右侧放⼊(尾插)到 list 中。                                                                                                                                                                                                     语法:                                                                                                                                                                                                     RPUSH key element [element ...]                                                                                                                                                                                                     时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.                                                                                                                                                                                                     返回值:插⼊后 list 的⻓度。                                                                                                                                                                                                    RPUSHX

                                                                                                                                     在 key 存在时,将⼀个或者多个元素从右侧放⼊(尾插)到 list 中。                                                                                                                                                                                                        语法:                                                                                                                                                                                                        RPUSHX key element [element ...]                                                                                                                                                                                                        时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.                                                                                                                                                                                                        返回值:插⼊后 list 的⻓度。                                                                                                                                                                                                       LRANGE

                                                                                                                                       获取从 start 到 end 区间的所有元素,左闭右闭。                                                                                                                                                                                                           语法:                                                                                                                                                                                                           LRANGE key start stop                                                                                                                                                                                                           
                                                                                                                                                                                                          时间复杂度:O(N)                                                                                                                                                                                                           返回值:指定区间的元素。                                                                                                                                                                                                           LPOP(头删)

                                                                                                                                         从 list 左侧取出元素(即头删)。                                                                                                                                                                                                              语法:                                                                                                                                                                                                              LPOP key                                                                                                                                                                                                              
                                                                                                                                                                                                             时间复杂度:O(1)                                                                                                                                                                                                              返回值:取出的元素或者 nil。                                                                                                                                                                                                              RPOP(尾删)

                                                                                                                                           从 list 右侧取出元素(即尾删)。                                                                                                                                                                                                                 语法:                                                                                                                                                                                                                 RPOP key                                                                                                                                                                                                                 
                                                                                                                                                                                                                时间复杂度:O(1)                                                                                                                                                                                                                 返回值:取出的元素或者 nil。                                                                                                                                                                                                                LINDEX

                                                                                                                                             获取从左数第 index 位置的元素。                                                                                                                                                                                                                    语法:                                                                                                                                                                                                                    LINDEX key index                                                                                                                                                                                                                    
                                                                                                                                                                                                                   时间复杂度:O(N)                                                                                                                                                                                                                    返回值:取出的元素或者 nil                                                                                                                                                                                                                   LINSERT

                                                                                                                                               在特定位置插⼊元素。                                                                                                                                                                                                                       语法:                                                                                                                                                                                                                       LINSERT key <BEFORE | AFTER> pivot element                                                                                                                                                                                                                       
                                                                                                                                                                                                                      时间复杂度:O(N)                                                                                                                                                                                                                       返回值:插⼊后的 list ⻓度。                                                                                                                                                                                                                       LLEN

                                                                                                                                                 获取 list ⻓度。                                                                                                                                                                                                                          语法:                                                                                                                                                                                                                          LLEN key                                                                                                                                                                                                                          
                                                                                                                                                                                                                         时间复杂度:O(1)                                                                                                                                                                                                                          返回值:list 的⻓度。                                                                                                                                                                                                                        
                                                                                                                                                LREM

                                                                        指定元素精准删除
                                                                        

                                                                        1.当count>0时,从头开始删除指定元素的次数
                                                                        

                                                                        2.当count<0时,从尾开始删除指定元素的次数
                                                                        

                                                                        3.当count=0时,删除全部指定的元素
                                                                        

                                                                        LTRIM

                                                                        只保留范围内的元素
                                                                        

                                                                        

                                                                        LSET
                                                                        根据下标修改元素
                                                                        

                                                                        

                                                                                                                                                壅闭版本下令

                                                                                                                                                 blpop 和 brpop 是 lpop 和 rpop 的壅闭版本,和对应⾮壅闭版本的作⽤根本⼀致,除了:                                                                                                                                                                                                                          •                                                                                                                                                                                                                          在列表中有元素的环境下,壅闭和⾮壅闭表现是⼀致的。但如果列表中没有元素,⾮壅闭版本会理                                                                                                                                                                                                                          解返回 nil,但壅闭版本会根据 timeout,壅闭⼀段时间,期间 Redis 可以执⾏其他下令,但要求执                                                                                                                                                                                                                          ⾏该下令的客⼾端会表现为壅闭状态(如图 2-22 所⽰)。                                                                                                                                                                                                                          •                                                                                                                                                                                                                          下令中如果设置了多个键,那么会从左向右进⾏遍历键,⼀旦有⼀个键对应的列表中可以弹出元                                                                                                                                                                                                                          素,下令⽴即返回。                                                                                                                                                                                                                          •                                                                                                                                                                                                                          如果多个客⼾端同时多⼀个键执⾏ pop,则开始执⾏下令的客⼾端会得到弹出的元素。                                                                                                                                                                                                                         BLPOP

                                                                                                                                                   LPOP 的壅闭版本。                                                                                                                                                                                                                             语法:                                                                                                                                                                                                                             BLPOP key [key ...] timeout                                                                                                                                                                                                                             时间复杂度:O(1)                                                                                                                                                                                                                             返回值:取出的元素或者 nil。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              BRPOP

   RPOP 的壅闭版本。     语法:     BRPOP key [key ...] timeout     时间复杂度:O(1)     返回值:取出的元素或者 nil。        
    内部编码

     列表范例的内部编码有两种:        •     ziplist(压缩列表):

     当列表的元素个数⼩于 list-max-ziplist-entries 设置(默认 512 个),同时        列表中每个元素的⻓度都⼩于 list-max-ziplist-value 设置(默认 64 字节)时,Redis 会选⽤        ziplist 来作为列表的内部编码实现来减少内存斲丧。     linkedlist(链表):

     当列表范例⽆法满⾜ ziplist 的条件时,Redis 会使⽤ linkedlist 作为列表的内部实现。     quicklist

  每个节点都是一个压缩列表,以链表的形式连接起来
     
      
       使⽤场景

   作为数组

   

   消息队列

       如图 2-22 所⽰,Redis 可以使⽤ lpush + brpop 下令组合实现经典的壅闭式⽣产者-斲丧者模型队列,⽣产者客⼾端使⽤ lpush 从列表左侧插⼊元素,多个斲丧者客⼾端使⽤ brpop 下令壅闭式地从队列中"争抢" 队⾸元素。通过多个客⼾端来保证斲丧的负载均衡和⾼可⽤性。         
               分频道的消息队列              如图 2-23 所⽰,Redis 同样使⽤ lpush + brpop 下令,但通过不同的键模仿频道的概念,不同的斲丧者可以通过 brpop 不同的键值,实现订阅不同频道的理念。              
         
          微博 Timeline

         每个⽤⼾都有属于⾃⼰的 Timeline(微博列表),现须要分⻚展⽰⽂章列表。此时可以考虑使⽤              列表,因为列表不但是有序的,同时⽀持按照索引范围获取元素。                   1)每篇微博使⽤哈希结构存储,比方微博中 3 个属性:title、timestamp、content:                 hmset mblog:1 title xx timestamp 1476536196 content xxxxx                 ...                 hmset mblog:n title xx timestamp 1476536196 content xxxxx                 2)向⽤⼾ Timeline 添加微博,user:<uid>:mblogs 作为微博的键:                 lpush user:1:mblogs mblog:1 mblog:3                 ...                 lpush user:k:mblogs mblog:9                 3)分⻚获取⽤⼾的 Timeline,比方获取⽤⼾ 1 的前 10 篇微博:                 keylist = lrange user:1:mblogs 0 9                 for key in keylist {                 hgetall key                 }                            此⽅案在现实中大概存在两个题目:                 1.       1 + n 题目。即如果每次分⻚获取的微博个数较多,须要执⾏多次 hgetall 操作,此时可以考虑使⽤pipeline(流⽔线)模式批量提交下令,或者微博不采⽤哈希范例,⽽是使⽤序列化的字符串范例,使⽤ mget 获取。                 2.       分裂获取⽂章时,lrange 在列表两端表现较好,获取列表中间的元素表现较差,此时可以考虑将列表做拆分。                 
          4.set集合

           集合范例也是生存多个字符串范例的元素的,但和列表范例不同的是,集合中 1)元素之间是⽆序                 的 2)元素不答应重复,如图 2-24 所⽰。⼀个集合中最多可以存储 个元素。Redis 除了⽀持                 集合内的增删查改操作,同时还⽀持多个集合取交集、并集、差集,合理地使⽤好集合范例,能在现实开发中解决许多题目。                set这个术语有不同的含义,如果是集合的话,就是把有关联的数据联系在一起,集合中的元素是无序的,集合中的元素是唯一的,集合中的每个元素都是string范例的                根本下令

      SADD

             将⼀个或者多个元素添加到 set 中。注意,重复的元素⽆法添加到 set 中。                    语法:                    SADD key member [member ...]                    
                   时间复杂度:O(1)                    返回值:本次添加成功的元素个数                   SMEMBERS

               获取⼀个 set 中的所有元素,注意,元素间的顺序是⽆序的。                       语法:                       SMEMBERS key                       
                      时间复杂度:O(N)                       返回值:所有元素的列表。                       SISMEMBER

                 判定⼀个元素在不在 set 中。                          语法:                          SISMEMBER key member                          
                         时间复杂度:O(1)                          返回值:1 表⽰元素在 set 中。0 表⽰元素不在 set 中或者 key 不存在。                         SCARD

                   获取⼀个 set 的基数(cardinality),即 set 中的元素个数。                             语法:                             SCARD key                             
                            时间复杂度:O(1)                             返回值:set 内的元素个数。                             SPOP

                     从 set 中删除并返回⼀个或者多个元素。注意,由于 set 内的元素是⽆序的,所以取出哪个元素现实是未界说⾏为,即可以看作随机的。                                语法:                                SPOP key [count]                                
                               时间复杂度:O(N), n 是 count                                返回值:取出的元素。                                srandmember                               从set中随机获取一个元素,但是不会移除该元素                              
                               SMOVE

                       将⼀个元素从源 set 取出并放⼊⽬标 set 中。                                   语法:                                   SMOVE source destination member                                   
                                  时间复杂度:O(1)                                   返回值:1 表⽰移动成功,0 表⽰失败                                  SREM

                         将指定的元素从 set 中删除。                                      语法:                                      SREM key member [member ...]                                      
                                     时间复杂度:O(N), N 是要删除的元素个数.                                      返回值:本次操作删除的元素个数。                                     集合间操作

                           交集(inter)、并集(union)、差集(diff)的概念如图 2-25 所⽰。                                       
                                        SINTER

                             获取给定 set 的交集中的元素。                                            语法:                                            SINTER key [key ...]                                            
                                           时间复杂度:O(N * M), N 是最⼩的集合元素个数. M 是最⼤的集合元素个数.                                            返回值:交集的元素。                                           SINTERSTORE

                               获取给定 set 的交集中的元素并生存到⽬标 set 中。                                               语法:                                               SINTERSTORE destination key [key ...]                                               
                                              时间复杂度:O(N * M), N 是最⼩的集合元素个数. M 是最⼤的集合元素个数.                                               返回值:交集的元素个数。                                               

                SUNION

                                 获取给定 set 的并集中的元素。                                                  语法:                                                  SUNION key [key ...]                                                  
                                                 时间复杂度:O(N), N 给定的所有集合的总的元素个数.                                                  返回值:并集的元素。                                                 SUNIONSTORE

                                   获取给定 set 的并集中的元素并生存到⽬标 set 中。                                                     语法:                                                     1                   SUNIONSTORE destination key [key ...]                                                     
                                                    时间复杂度:O(N), N 给定的所有集合的总的元素个数.                                                     返回值:并集的元素个数。                                                     SDIFF

                                     获取给定 set 的差集中的元素。                                                        语法:                                                        SDIFF key [key ...]                                                        
                                                      
                                                       时间复杂度:O(N), N 给定的所有集合的总的元素个数.                                                        返回值:差集的元素。                                                                       SDIFFSTORE

                                     获取给定 set 的差集中的元素并生存到⽬标 set 中。                                                        语法:                                                        SDIFFSTORE destination key [key ...]                                                        
                                                       时间复杂度:O(N), N 给定的所有集合的总的元素个数.                                                        返回值:差集的元素个数                                    下令小结

                  

                  内部编码

                                     集合范例的内部编码有两种:                                                                            •                                       intset(整数集合):

                                       当集合中的元素都是整数而且元素的个数⼩于 set-max-intset-entries 设置                                                           (默认 512 个)时,Redis 会选⽤ intset 来作为集合的内部实现,从⽽减少内存的使⽤。                                                           •                                       hashtable(哈希表):

                                       当集合范例⽆法满⾜ intset 的条件时,Redis 会使⽤ hashtable 作为集合                                                           的内部实现。                                                         
                                                                              使⽤场景

                                         集合范例⽐较典范的使⽤场景是标签(tag)。比方 A ⽤⼾对娱乐、体育板块⽐较感爱好,B ⽤⼾                                                              对历史、新闻⽐较感爱好,这些爱好点可以被抽象为标签。有了这些数据就可以得到喜欢同⼀个标签的⼈,以及⽤⼾的共同喜好的标签,这些数据对于增强⽤⼾体验和⽤⼾黏度都⾮常有帮助。 比方⼀个电⼦商务⽹站会对不同标签的⽤⼾做不同的产品保举。                                         1.使用set来生存用户的标签

                                         
                                        2.使用set来计算共同好友,基于集合求交集

                                         
                                                             3.使用set来计算uv                                                            
                                                             Zset 有序集合

                                           有序集合相对于字符串、列表、哈希、集合来说会有⼀些陌⽣。它保留了集合不能有重复成员的                                                                 特点,但与集合不同的是,有序集合中的每个元素都有⼀个唯⼀的浮点范例的分数(score)与之关联,着使得有序集合中的元素是可以维护有序性的,但这个有序不是⽤下标作为排序依据⽽是⽤这个分数。如图 2-26 所⽰,该有序集合显⽰了三国中的武将的武⼒                                                               
                                                                                       有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能,合理地利⽤有序集合,可                                                                    以帮助我们在现实开发中解决许多题目。                                                                  
                                                                  
                                            常见下令

                      zadd

                                             添加或者更新指定的元素以及关联的分数到 zset 中,分数应该符合 double 范例,+inf/-inf 作为正负                                                                    极限也是合法的。                                                                    ZADD 的相关选项:                                                                    XX:仅仅⽤于更新已经存在的元素,不会添加新元素。                                                                    NX:仅⽤于添加新元素,不会更新已经存在的元素。                                                                    CH:默认环境下,ZADD 返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。                                                                    INCR:此时下令雷同 ZINCRBY 的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和分数。                                                                  
                                                                   ZCARD

                                               获取⼀个 zset 的基数(cardinality),即 zset 中的元素个数。                                                                     
                                                                      ZCOUNT

                                                 返回分数在 min 和 max 之间的元素个数,默认环境下,min 和 max 都是包含的,可以通过 (,表示开区间                                                                        
                                                                        
                                                                         ZRANGE

                                                   返回指定区间⾥的元素,分数按照升序。带上 WITHSCORES 可以把分数也返回。                                                                             
                                                                            ZREVRANGE

                                                     返回指定区间⾥的元素,分数按照降序。带上 WITHSCORES 可以把分数也返回。                                                                                备注:这个下令大概在 6.2.0 之后废弃,而且功能归并到 ZRANGE 中。                                                                              
                                                                               ZRANGEBYSCORE

                                                       返回分数在 min 和 max 之间的元素,默认环境下,min 和 max 都是包含的,可以通过 ( 清除。                                                                                   备注:这个下令大概在 6.2.0 之后废弃,而且功能归并到 ZRANGE 中。                                                                                   
                                                                                  ZPOPMAX

                                                         删除并返回分数最⾼的 count 个元素。                                                                                    
                                                                                     BZPOPMAX

                                                           ZPOPMAX 的壅闭版本。                                                                                         
                                                                                        ZPOPMIN

                                                             删除并返回分数最低的 count 个元素。                                                                                            BZPOPMIN

                                                               ZPOPMIN 的壅闭版本。                                                                                              ZRANK

                                                                 返回指定元素的排名,升序。                                                                                                  
                                                                                                 ZREVRANK

                                                                   返回指定元素的排名,降序。                                                                                                     
                                                                                                    ZSCORE

                                                                     返回指定元素的分数。                                                                                                        
                                                                                                       ZREM

                                                                       删除指定的元素。                                                                                                           
                                                                                                          ZREMRANGEBYRANK

                                                                         按照排序,升序删除指定范围的元素,左闭右闭。                                                                                                            
                                                                                                             ZREMRANGEBYSCORE

                                                                           按照分数删除指定范围的元素,左闭右闭。                                                                                                                 
                                                                                                                ZINCRBY

                                                                             为指定的元素的关联分数添加指定的分数值                                                                                                                  
                                                                                                                   集合间操作

                                       

                                       ZINTERSTORE(交集)

                                       

                                       
                                                                               求出给定有序集合中元素的交集并生存进⽬标有序集合中,在归并过程中以元素为单位进⾏归并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数。                                                                                                                     
                                                                                                                                                               时间复杂度:O(N*K)+O(M*log(M)) N 是输⼊的有序集合中, 最⼩的有序集合的元素个数; K 是输⼊了⼏个有序集合; M 是最闭幕果的有序集合的元素个数.                                                                                                                       ZUNIONSTORE并集

                                       
                                                                               求出给定有序集合中元素的并集并生存进⽬标有序集合中,在归并过程中以元素为单位进⾏归并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数。                                                                                                                       语法:                                                                                                                       ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight                                                                                                                       [weight ...]] [AGGREGATE <SUM | MIN | MAX>]                                                                                                                       时间复杂度:O(N)+O(M*log(M)) N 是输⼊的有序集合总的元素个数; M 是最闭幕果的有序集合的元素个数.                                                                                                                       返回值:⽬标集合中的元素个数                                                                              

                                       下令⼩结

                                       

                                       

                                                                              内部编码

                                                                               有序集合范例的内部编码有两种:                                                                               ziplist(压缩列表):

                                       当有序集合的元素个数⼩于 zset-max-ziplist-entries 设置(默认 128 个), 同时每个元素的值都⼩于 zset-max-ziplist-value 设置(默认 64 字节)时,Redis 会⽤ ziplist 来作

                                                                               为有序集合的内部实现,ziplist 可以有效减少内存的使⽤。                                                                               skiplist(跳表):

                                                                               当 ziplist 条件不满⾜时,有序集合会使⽤ skiplist 作为内部实现,因为此时ziplist 的操作效率会降落                                                                                                                                                               1)当元素个数较少且每个元素较⼩时,内部编码为 ziplist:                                                                                                                          2)当元素个数超过 128 个,内部编码 skiplist:                                                                                                                          3)当某个元素⼤于 64 字节时,内部编码 skiplist:                                                                                使⽤场景

                                       
                                                                                 有序集合⽐较典范的使⽤场景就是排⾏榜系统。比方常⻅的⽹站上的热榜信息,榜单的维度大概                                                                                                                          是多⽅⾯的:按照时间、按照阅读量、按照点赞量。本例中我们使⽤点赞数这个维度,维护每天的热榜:                                                                                                                        

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

干翻全岛蛙蛙

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表