当前位置: 首页 > 科技观察

Redis基础知识及应用场景_0

时间:2023-03-15 19:07:02 科技观察

什么是redis?Redis是互联网技术领域应用最广泛的存储中间件。它是“RemoteDictionaryService”的缩写,即“远程词典服务”。Redis以其超高性能、完善的文档、简洁易懂的源代码、丰富的客户端库支持,在开源中间件领域广受好评。国内外很多大型互联网公司都在使用Redis,比如Twitter、YouPorn、暴雪娱乐、Github、StackOverflow、腾讯、阿里、京东、华为、新浪微博等,很多中小型公司也有应用.也可以说,对Redis的理解和应用实践已经成为中高级后端开发者不可或缺的技能。Redis可以做什么记录帖子的点赞数、评论数和点击数(哈希)。记录用户的帖子ID列表(排序),用于快速显示用户的帖子列表(zset)。记录帖子的标题、摘要、作者和封面信息,用于列表页展示(hash)。喜欢帖子的用户ID列表,评论ID列表,用于显示和去重计数(zset)。缓存近期热帖内容(帖子内容占用空间大),降低数据库压力(hash)。记录帖子的相关文章ID,根据内容推荐相关帖子(列表)。如果帖子ID是整数自增,可以使用Redis分配帖子ID(计数器)。集合和帖子之间的关系(zset)。记录趋势帖子ID、总趋势和类别趋势(zset)的列表。缓存用户行为历史,进行恶意行为过滤(zset、hash)。......等等Redis基本数据结构及相关应用介绍大家也可以看我之前关于基本数据结构的文章《换一种存储方式,居然能节约这么多内存?》。字符串实现方式:动态字符串;内部结构类似于Java的ArrayList;采用预分配冗余空间的方法,减少内存的频繁分配。当字符长度<1M时,扩展时将现有空间加倍。当字符串>1M时,扩展时每次增加1M,字符串最大长度为512M。字符串由多个字节组成,每个字节由8位组成。字符串被看作是位的组合,是位图(bitmap)数据结构。命令setkey的实现方法;getkeylist:链表实现类似于java中的LinkList。在数据量小的情况下,使用fastlist,在数据量小的情况下,使用连续内存,ziplist数据结构。数据量大的时候用linkedlist,linkedlist和ziplist结合。这样的好处:既满足了快速插入和删除的性能,又不会造成过多的空间冗余。经典应用:异步队列需要注意的是,lindex是一个时间复杂度为O(n)的慢操作,谨慎使用。空队列可能会导致CPU空闲,也可能会提高qps。可以使用阻塞读取:blpop/brpop命令rpushrphash类似于java中的HashMap,数组+链表的二维结构。数据量小的时候是ziplist。与HashMap相比:rediskey只能是字符串,rehash方式不同。set类似于javaHashSet。应用场景:保存获胜用户的id,带去重功能命令saddsmemberskey获取所有keysismemberkeysetv相当于contains(s)scardkey返回key个数spopkeys:RedisSpop命令用于去除set中指定的一个或多个随机元素的key。Zset类似于javaSortedSet和HashMap的结合;concurrentskipmap内部实现了“跳转列表”的数据结构。当数据较少时使用ziplist。当有大量数据时使用skiplist。注:关于过期时间,单位为对象。如果设置了过期时间,然后调用set修改对象,过期时间就会消失。经典应用粉丝榜:值ID,分数跟随时间分布式锁:redis2.8增加了set命令的扩展参数,使得setnx和expire命令可以一起执行。jredis命令:StringUtils.equals("OK",redis.set("seemoonup","false","NX","EX",5))这条命令完整的意思是如果key"seemoonup"没有存在,则设置为“false”并设置5秒的过期时间。这种实现的缺点:没有ack(消息确认机制)保证。位图的最小单位位(bit)只能是0。1bitfield有get/set/incrby三个子命令,可以读写指定的位段,但最多只能处理64个连续的位。64位,你必须使用多个子命令,bitfield可以一次执行多个子命令bitmapsetbitbitcountredis高级应用HyperLogLog这是一种高级数据结构,提供了一种不准确的去重计数方案,错误率为0.81%。应用场景中高流量页面的UV不适合单用户存储。实现方式:Redis优化了HyperLogLog的存储。当count比较小时,它的存储空间用稀疏矩阵存储,占用空间小。只有当计数逐渐增加,稀疏矩阵占用的空间逐渐超过阈值时才会使用。一次转换为稠密矩阵会占用12k空间。为什么是12k?实现是16384个桶,也就是2的14次方。每个bucket的maxbtis需要6个字节的存储,即2的14次方*6/8=12k布隆过滤器(bloomfilter)优点:在去除权重的同时,还能节省90%的空间。注:有误判率,没有判断就一定没有;如果有,很可能会有。只有没看过的才会误判,误判率可以通过参数调整。原理:位图+哈希表,一个大数组(位图)+几个无偏哈希函数,位图越稀疏,正确率越高。redis4.0之后才有;我们平时使用的HBase、Cassandra、LevelDB、RocksDB内部都有Bloomfilter结构,Bloomfilter可以显着减少数据库的IO请求数。当用户查询某一行时,可以先通过内存中的Bloomfilter过滤掉大量不存在的行请求,然后去磁盘查询HBase,cassandralevelDB,RocksDB都有开发的Bloomfilter结构谷歌。Guava库提供了布隆过滤器的实现。使用zset实现简单的电流限制。应用原理:zset;key=user+behavior,vaule=timestamp,score=timestamp使用pipline:一次发送多个命令,zremrangebyscore命令用于移除有序集合中指定score区间内的所有成员zremrangebyscore(key,0,时间窗口*1000)缺点:不适合大量使用,会占用大量存储空间。例如60s内的操作不能超过100万次。漏斗限流redis4.0提供了一个限流模块Redis-Cell,它使用的是漏斗算法。这个模块是用Rust语言编写的。Redis是用C写的,这个模块只有一条指令cl.throttle。比如key每60s只能回复30次附近的人cl.throttlekey1530601GeoHash这是Redis在3.2版本之后新增的Geo模块。原理:在redis中,经纬度用52位整数编码,放在zset中;zset值为key,score为GeoHash的52位整数值,命令geoaddcompany116.48139.996xiaomi计算两点距离geodiscompanyjuejinxiaomikk得到元素位置geoposconpanyxiaomi得到元素哈希值geohashcompanyxiaomiNearbycompanygeoradiusbymembercompanyxiaomi20kmcount320km范围内,最多3个元素按距离排列,不会排斥自身。建议使用单独的Redis实例部署Geo数据库。如果数据量超过1亿甚至更大,就需要拆分。它可以按国家、省或城市拆分,以减少单个zset集合的大小。Redis大海捞针-key遍历keys没有偏移限制参数keys遍历算法,时间复杂度为O(n)。如果实例中有数千万个key,keys命令会造成卡顿。Redis是单线程数据。Redis2.8版本新增扫描扫描。虽然复杂度也是O(n),但是通过游标一步步执行,不会阻塞线程。提供limit参数来控制每次返回的最大结果数。与键一样,也有模式匹配功能。服务器不需要保存游标的状态。请注意,返回的结果可能会重复。如果在客户端去重遍历过程中修改了数据,可能会返回Incorrectdata。返回一个空的单个结果并不意味着遍历结束。取决于返回的cursor值是否为0。limit不限制返回结果的个数,而是限制服务器单次遍历的字典槽数(约等于)scan0matchkey99*count10字典结构。Redis中的所有键都存在于一个大字典中。数据结构类似于java的HashMap数据结构。一维数组+二维链表。大小和空间翻倍,2的N+1次方返回的扫描命令是一维数组的位置索引。这就是槽(slot)扫描返回空的原因,因为有些槽是空的。scan遍历高位进位加减考虑到字典的扩缩容,避免槽的重复和遗漏,从左开始加法与普通加法相反,使用[高位进位加减]rehash后的槽与遍历顺序相邻的progressiverehash扩容,同时保存新旧数组。按照hash上的指令操作,将旧数组中附加的元素迁移到新数组中。回收占用大量内存,导致扫描判断key大小太麻烦。redis-cli命令提供了扫描功能redis-cli-h127.0.0.1-p7001--bigkeys,防止redis的ops过大引起告警。可以添加修改参数redis-cli-h127.0.0.1-p7001--bigkeys-i0.1