当前位置: 首页 > 后端技术 > Java

高级Java开发工程师-简单Redis

时间:2023-04-01 14:25:23 Java

作者:Magic来源:恒生LIGHT云社区基本介绍什么是Redis?Redis是互联网技术领域应用最广泛的存储中间件。它是“RemoteDictionaryService”的缩写,即“远程词典服务”。Redis以其超高性能、完善的文档、简洁易懂的源代码、丰富的客户端库支持,在开源中间件领域广受好评。国内外很多大型互联网公司都在使用Redis,比如Twitter、YouPorn、暴雪娱乐、Github、StackOverflow、腾讯、阿里、京东、华为、新浪微博等,很多中小型公司也有应用.也可以说,对Redis的理解和应用实践已经成为中高级后端开发者不可或缺的技能。Redis可以用来做什么?》Redis是一个开源(BSD许可)、内存数据结构存储系统,可以作为数据库、缓存、消息中间件使用。它支持多种类型的数据结构,如字符串、散列(hashes)、列表,sets,sortedsetsandrangequeries,bitmaps,hyperloglogsandgeospatialindexradiusqueries.Redis内置了复制,LUA脚本(Luascripting),LRU驱动事件(LRUeviction),事务(transactions)和不同级别的磁盘持久化(persistence),通过Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用(highavailability)。Redis能做什么?Redis有广泛的业务应用,以博客社区的功能模块作为例子:记录帖子的点赞数、评论数和点击数(hash)记录用户的帖子ID列表(排序),方便快速展示用户的帖子列表(zset)记录标题、摘要、作者和列表页面上显示的帖子封面信息(哈希)。记录点赞用户id列表和评论id列表,用于展示和去重统计(zset)。缓存近期热帖内容(帖子内容占用空间大),降低数据库压力(hash)。Redis下载安装参考网站:http://www.redis.cn/download.html基本数据结构Redis有5种基本数据结构,分别是:字符串(string)、列表(list)、散列(hash)、集合(set)和zset(有序集)。熟练使用这五种基本数据结构是Redis知识中最基础也是最重要的部分。String(字符串)——字符串的基本概念字符串是Redis最简单的数据结构。所有的Redis数据结构都使用一个唯一的键字符串作为名字,然后使用这个唯一的键值来获取对应的值数据。不同类型数据结构的区别在于值的结构不同。-string的应用字符串结构被广泛使用,一个常见的用途是缓存用户信息。我们使用JSON将用户信息结构序列化为字符串,然后将序列化后的字符串塞入Redis进行缓存。同样,获取用户信息也会经过一个反序列化过程。-字符串的结构原理Redis字符串是可以修改的动态字符串。内部结构类似于Java的ArrayList,采用预先分配冗余空间的方式来减少内存的频繁分配。如图所示,内部实际为当前字符串分配的容量一般要高于实际字符串长度len。当字符串长度小于1M时,扩容会将现有空间扩大一倍。如果超过1M,扩容一次只会扩容1M空间。需要注意的是字符串最大长度为512M。一个字符串由多个字节组成,每个字节由8位组成,所以一个字符串可以看成是很多位的组合。这就是位图“位图”数据结构。-字符串操作命令基本命令:set、get、exists、del批量命令:mset、mget其他命令:expire、setex、setnx、incr、incrby如果值为整数,则可以自增。自增是有范围的,它的范围就是signedlong的最大值和最小值。如果超过这个值,Redis就会报错。列表(list)——列表的基本概念Redis列表相当于Java语言中的LinkedList,注意是链表而不是数组。这意味着列表的插入和删除操作非常快,O(1)时间复杂度,但是索引定位很慢,O(n)时间复杂度。当列表中的最后一个元素被弹出时,数据结构被自动删除并回收内存。-list的应用Redis的链表结构经常被用作异步队列。将需要延迟的任务结构序列化为字符串塞入Redis列表,另一个线程从这个列表中轮询数据进行处理。-如果深入研究链表的结构原理,你会发现Redis链表的底层存储并不是简单的链表,而是一种叫做快速链表的结构。首先,当列表元素较少时,会使用连续的内存存储。这个结构就是ziplist,就是一个压缩列表。它将所有元素并排存储,并分配一块连续的内存。当列表元素较多时,会改为quicklist。因为普通链表需要的额外指针空间太大,会浪费空间,增加内存碎片。比如这个链表只存放了int类型的数据,结构中还需要额外增加两个指针prev和next。所以Redis将链表和ziplist结合起来形成了quicklist。即多个ziplists使用双向指针串联使用。这样既满足了快速插入删除的性能,又不会造成过多的空间冗余。-列表操作命令常用命令:rpush,lpush,rpop,lpop查询命令:llen,lrange,lindex,ltirm哈希/字典(hash)-哈希的基本概念Redis字典相当于Java语言中的HashMap,即无序字典.内部实现结构也和Java的HashMap一致,同样是数组+链表的二维结构。-hash结构原理当第一维hash的数组位置发生碰撞时,碰撞的元素将使用链表串连接起来。不同的是Redis字典的值只能是字符串,它们的rehash方式不同,因为当Java的HashMap字典很大时,rehash是一个比较耗时的操作,需要一次性全部rehash。Redis为了高性能,不能阻塞服务,所以采用了渐进式rehash策略。Progressiverehash会在rehash的同时保留新旧hash结构,查询时同时查询这两个hash结构,然后在后续定时任务和hash子命令中逐渐将旧hash的内容迁移到新的hash结构中。当哈希删除最后一个元素时,数据结构会自动删除并回收内存。哈希也有缺点。哈希结构的存储消耗高于单个字符串。使用hash还是string需要根据实际情况权衡。-哈希的应用哈希结构还可以用来存储用户信息。与字符串需要一次序列化整个对象不同,哈希可以将用户结构中的每个字段单独存储。当我们需要获取用户信息时,可以部分获取。但是,如果用户信息以整个字符串的形式保存,则只能一次全部读取,会浪费网络流量。-hash操作命令常用命令:hset,hget,hgetall,hlen,hmet其他命令:hincr,hincrbuset(set)-set基本概念Redisset相当于Java语言中的HashSet,其内部键值对是Unorderedunique.它的内部实现相当于一个特殊的字典,字典中的所有值都是一个值NULL。当集合中的最后一个元素被移除时,数据结构被自动删除并回收内存。-set应用的set结构体可以用来存储活动获胜者的用户ID,因为去重功能可以保证同一个用户不会两次中奖。-set操作命令常用命令:sadd、smembers、sismember、scard、spop-set结构原理set对象set是string类型的无序集合(整数也会转成string类型存储)。注意集合和列表的区别:集合中的元素是无序的,所以不能通过索引来操作元素;集合中的元素不能重复。编码后的集合对象的编码可以是intset,也可以是hashtable。intset编码的集合对象使用整型集合作为底层实现,集合对象中包含的所有元素都存储在整型集合中。哈希表编码的集合对象使用字典作为底层实现。字典的每个键都是一个字符串对象,这里的每个字符串对象都是一个集合中的一个元素,字典的值都设置为null。这可以类比为Java集合中HashSet集合的实现。HashSet集合是由HashMap实现的。集合中的元素是HashMap的键,HashMap的值都设置为null。编码转换当set同时满足以下两个条件时,使用intset编码:set对象中的所有元素都是整数,并且set对象中所有元素的个数不超过512。如果不能满足这两个条件,使用哈希表编码。第二个条件可以通过配置文件的set-max-intset-entries来配置。有序集合(zset)——zset的基本概念zset可能是Redis提供的最具特色的数据结构,也是面试官面试时爱问的数据结构。它类似于Java的SortedSet和HashMap的组合。一方面,它是一个集合,保证了内部值的唯一性。另一方面,它可以为每个值分配一个分数,代表这个值的排序权重。它的内部实现使用一种称为“跳转列表”的数据结构。zset中的最后一个值被移除后,数据结构自动删除,内存被回收。-zsetzset的应用可以用来保存粉丝列表,value值是粉丝的用户ID,score是关注时间。我们可以按照关注时间对关注者列表进行排序。zset也可以用来存储学生的成绩,value值就是学生的id,score就是他的考试成绩。我们可以按照分数对结果进行排序,得到他的排名。-zset的操作命令常用命令:zadd、zrange、zrevrange、zcard、zscore、zrank、zrangebyscore-Zset的结构原理有序集合对象是有序的。与使用索引下标作为排序依据的列表不同,有序集合为每个元素设置一个分数作为排序依据。编码有序集合的编码可以是ziplist或skiplist。ziplist编码的有序集合对象使用压缩列表作为底层实现。每个集合元素都使用两个彼此相邻的压缩列表节点进行存储。第一个节点存储元素的成员,第二个节点存储元素的分数。.并且压缩列表中的集合元素按照分值从小到大的顺序排列,小的放在靠近表头的位置,大的放在靠近表尾的位置。skiplist编码的有序集合对象使用zset结构作为底层实现。一个zset结构同时包含一个字典和一个skiptable:字典的key存放元素的值,字典的值存放元素的score;跳表节点的object属性保存元素的成员,跳表节点的score属性保存元素的分数。这两个数据结构会通过指针共享同一个元素的成员和值,所以不会出现重复的成员和值,造成内存浪费。编码转换当一个有序集合对象同时满足以下两个条件时,该对象使用ziplist编码:存储元素个数小于128;所有存储元素的长度小于64字节;如果不能满足以上两个条件,则使用skiplist编码。以上两个条件可以通过Redis配置文件zset-max-ziplist-entries选项和zset-max-ziplist-value修改。容器类数据结构的通用规则list/set/hash/zset这四种数据结构都是容器类数据结构,它们共有以下两条通用规则:不存在则创建如果容器不存在,则创建一个,然后操作。比如rpush操作一开始没有list,redis会自动创建一个,然后rpush入新元素dropifnoelements如果容器中没有元素,则立即删除该元素,释放内存。这意味着lpop对最后一个元素进行操作并且列表消失。过期时间Redis中的所有数据结构都可以设置过期时间。当时间到了,Redis会自动删除对应的对象。需要注意的是,过期是以对象为单位的。例如,哈希结构的过期是整个哈希对象的过期,而不是其中一个子密钥的过期。特别注意的是,如果一个字符串设置了过期时间,然后你调用set方法修改它,它的过期时间就会消失。