redis系列(一)redis基础

    xiaoxiao2021-03-26  31

    redis简介  redis的特点redis的应用场景

    1  redis简介

            redis是一个远程内存数据库,是一种非关系型数据库,它在内存中是以key-value的形式存储数据的,类似与Memcached,但是不同的是它有五种类型的数据结构。各式各样的问题都可以很自然地映射到这些数据结构上:Redis的数据结构致力于帮助用户解决问题,而不会像其他数据库那样,要求用户扭曲问题来适应数据库。除此之外,通过复制、持久化(persistence)和客户端分片(client-side sharding)等特性,用户可以很方便地将Redis扩展成一个能够包含数百GB数据、每秒处理上百万次请求的系统。

    2  redis的特点

            首先它是一种数据库,要说它的特点,我们可以通过与其它的数据库进比较来看看它的特点。

    2.1  redis和关系型数据库的比较

           首先,我们先想一下关系型数据库的特点。关系型数据库的数据机构就是人们日常生活中常见的二维表结构,关系型数据库模型将数据看成是二维表中唯一的行号和列号确定的一个表中的元素,即关系型数据库是通过二维表的方式来组织、存储和处理数据和信息的。关系型数据库的存储引擎是一个B+或B-树,要说B+树之前我先说一下B树,所谓B树其实就是我们说的二叉树。在二叉树中所有的节点都存储一个关键字,如果查询的关键字和节点的关键字匹配,那么就命中,但是由于B树进行 多次插入和删除之后,可能导致变成一个不同于B树的结构。B+树其实就是B树之上B-树的变种,这里我们就不对B-树  进行多余的介绍了。B+树其实就是一种多路的搜索树,所有的关键字都存储在叶子节点上,不会出现在非叶子节点上,所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;B+树的搜索,B+树只有达到叶子结点才命中(B-树可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找。Redis 是支持多key-value数据库(表)的,并用 RedisDb 来表示一个key-value数据库(表)。redisDb 中 ,dict 成员是与实际存储数据相关的。dict 是主要是由 struct dictht 的哈唏表构成的,之所以定义成长度为2的( dictht ht[2] ) 哈唏表数组。是因为 redis 采用渐进的 rehash,即当需要 rehash 时,每次像 hset、hget 等操作前,先执行N 步 rehash, 这样就把原来一次性的 rehash过程拆散到进行, 防止一次性 rehash 期间 redis 服务能力大幅下降.,这种渐进的 rehash 需要一个额外的 struct dictht 结构来保存。struct dictht 主要是由一个 struct dictEntry 指针数组组成的,hash 表的冲突是通过链表法来解决的。struct dictEntry 中的 key 指针指向用 sds类型表示的 key 字符串, val 指针指向一个 struct redisObject 结构体。使用 Redis 而不是关系数据库或者其他硬盘存储数据库,可以避免写入不必要的临时数据,也免去了对临时数据进行扫描或者删除的麻烦,并最终改善程序的性能。关于redis的存储结构具体如何就不在这里介绍了,我会在后续的文章中做一个详细的说明。

             其次,关系型数据库由于需要在单机存储引擎层面支持索引,大大降低了系统的可扩展性,使得单机存储引擎的设计变得更复杂。而诸如redis的nosql数据库是在系统层面支持数据库的。

             还有就是join操作,我们知道在使用关系型数据库的时候,我们很多时候需要关联查询多张表来将多个表的数据查出来,这种关联的join操作效率是非常慢的,但是由于redis数据  结构的特点,我们不需要将想要查询的数据放到不同的表中,只需要放到一个相同的键值对中,这样虽然冗余存储了数据但是却提高了效率,但是我们可以这样考虑,很多人在使用 Mysql的过程遇到记录条数超过一定值,比如2000W的时候,数据库性能开始下降,这个值的得出往往需要经过大量的测试。然而,大多数的NoSQL系统(redis就是一种nosql数据库)可扩展性都比较好,能够支持更大的数据量,因此也可以采用一些空间换时间的做法,比如通过宽表的方式实现Join,这就是说像redis这种nosql数据库有更大的数据量。

            性能预估更加容易。关系型数据库由于复杂的并发控制,insert buffer及类似page cache的读写优化机制,性能估算相对较难,很多时候需要凭借经验或者经过测试才能得出系统 的性能。然后,NoSQL系统由于存储引擎实现,并发控制机制等相对简单,可以通过硬件的性能指标在系统设计之处大致预估系统的性能,性能预估可操作性相对更强。

    2.2  redis和memcached的比较

            这两者都可用于存储键值映射,彼此的性能也相差无几,但是Redis能够自动以两种不同的方式将数据写入硬盘,并且Redis除了能存储普通的字符串键之外,还可以存储其他4种数据结构,而memcached只能存储普通的字符串键。这些不同之处使得Redis可以用于解决更为广泛的问题,并且既可以用作主数据库(primary database)使用,又可以作为其他存储系统的辅助数据库(auxiliary database)使用。

            在使用redis这种内存数据库的时候,一个首先要考虑的问题就是当服务器被关闭的时候,服务器存储的数据何去何从呢?redis拥有两种不同的持久化方法,他们都可以用小而紧凑的格式将存储在内存中的数据导入硬盘,第一种持久化方法为时间点存储,转储操做既可以在指定时间段内由指定数量的操作执行。也可以通过调用两条转储到硬盘命令中的任何一条来执行;第二种持久化方法将所有修改了数据库的命令都写入一个只追加文件里面,用户可以根据数据的重要程度,将只追加写入设置为从不同步(sync)、每秒同步一次或者每写入一个命令就同步一次。

            memcached只有字符串这一种数据类型,但是redis有五种不同的数据类型(STRING、LIST、SET、HASH、ZSET),可以满足不同的需求。

    2.3  redis的其他特点

            尽管Redis的性能很好,但受限于Redis的内存存储设计,有时候只使用一台Redis服务器可能没有办法处理所有请求。因此,为了扩展Redis的读性能,并为Redis提供故障转移(failover)支持,Redis实现了主从复制特性:执行复制的从服务器会连接上主服务器,接收主服务器发送的整个数据库的初始副本(copy);之后主服务器执行的写命令,都会被发送给所有连接着的从服务器去执行,从而实时地更新从服务器的数据集。因为从服务器包含的数据会不断地进行更新,所以客户端可以向任意一个从服务器发送读请求,以此来避免对主服务器进行集中式的访问。

             其次 redis还有发布与订阅的功能。

    3  redis的应用

           Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储;它的数据模型非常独特,用的是单线程。你可以把它融入到你的系统中来,这就能够解决很多问题,比如那些你现有的数据库处理起来感到缓慢的任务。这些你就可以通过Redis来进行优化,或者为应用创建些新的功能。下面我们根据redis的特点和优点可以总结一些redis使用的场景。

    3.1  在主页中显示最新的项目列表

            在web应用中,列出最新的一定数量的记录是非常常见的事情,这通常会带来可扩展性问题,因为记录本来就是这么录入的,但要输出这个顺序却不得不进行排序操作。我们知道关系型数据库的数据是储存在硬盘上的,如果直接读取数据库的信息,我们需要将表中的数据全部排序之后再从中取出一部分想要的数据,如果数据量很 大的话,效率会很慢。但是如果使用redis的话,每次新增一个记录的时候,我们可以将它添加到一个redis列表中,我们可以指列表中的长度,既指定存放的数量,每次要获取一定数量的最新的记录的时候,我们可以redis的命令获取这个redis列表中的数据。这样相比起来,我们是直接获取内存中的数据,而且只是查询固定数量的记录,相比起来效率高了很多。

    3.2   排行榜相关

           由于各种数据库的数据并非存储在内存中的,因此按得分排序以及实时更新这些几乎每分每秒都需要更新数据的功能,一般的数据库性能很不理想。典型的比如游戏排行榜,你可能需要查询你所在区的,所在国家的游戏得分的排名。对于redis来说是小意思的,每次获取新得分之后,我们通过操作ZSET,ZADD GAMELIST SCORE USERNMAE ...,然后假如你要获取前一百名ZREVRANG GAMELIST 0 99,假如你要获取你自己的排名ZRANG GAMELIST USERNAME。

    3.3  按照用户投票和时间排序

           新闻信息会有一定的排名,排名一般是通过投票数和发布的时间来排序的,假如排序的算法是score = points/time^alpha,从这个算法中可以看出用户的投票或者时间会将时间。我第一次接触redis的项目就是一个广告的排序,通过点击量和时间来排序,道理和这个差不多。用户的点击量会把相应的广告提上去,但是时间会把一定的指数将广告埋下去。我们可以想一下传统的做法是什么样的,每次有新的新闻发布出来,先要插入到一个相应的数据库表中。然后想要获取排行的时候先查询所有的记录并算出每条记录的score,再将其作为新的记录按照score进行排序,去除一定的数据。这种新闻和广告之类的信息数据量是很大的,如果这样做,效率会相当慢。但是如果我们使用redis,我们先想一下思路,我们要使用redis,一定是将想要的数据放到redis的列表中的,但是数据是实时更新的,所以需要一个后台的任务去实时的更新这个记录。基于这样的思路,我们来实现一下,首先当有新闻发布出来的时候,我们将其添加到一个redis列表中,使用LPUSH+LTRIM确保只去除最新的一定数量的数据,有一个后台任务获取这个列表,并且持续的计算这些新闻中每条新闻的最终得分,计算结果由ZADD命令填写新的数据,剔除老数据。这样相比速率就快多了。

    3.4  计数

           Redis是一个很好的计数器,这要感谢INCRBY和其他相似命令。再做统计的时候,我们会想要在数据库上加上计数器来实现对应的功能,但是由于写入相当的麻烦没办法实现。假如我们要计算用户再页面停留不超过一分钟的页面浏览量,当计数器达到一定数量的时候就显示出某些条幅或者广告之类的,我想上过网的人都会见过这些情况吧。我们通过两个命令来实现计数INCR user<id> 和EXPIRE user<id> 60。INCR命令用于将键的整数值递增1。如果键不存在,则在执行操作之前将其设置为0。Expire命令用于设置键的到期时间。在到指定的到期时间后,在Redis中这个键将失效,不能再使用。

    3.5  特定的时间内特定的记录

           当我们需要统计在一个特定的时间内有多少特定的用户访问了某些特定的资源。每次我们获得一次新的页面浏览时我们只需要SADD page:time:<page_id> <user_id>,之后当你想知道特定用户的数量的时候,只需要SCARD page:time:<page_id>,当我们需要看看一个用户是否访问了某个页面的时候只需要SISMEMBER page:time:<page_id>。

    3.6  实时分析正在发生的情况,用于数据统计与防止垃圾邮件等

           我们只做了几个例子,但如果你研究Redis的命令集,并且组合一下,就能获得大量的实时分析方法,有效而且非常省力。使用Redis原语命令,更容易实施垃圾邮件过滤系统或其他实时跟踪系统。

    3.7  Pub/Sub

            Redis的Pub/Sub非常非常简单,运行稳定并且快速。支持模式匹配,能够实时订阅与取消频道。

    3.8   队列

             你应该已经注意到像list push和list pop这样的Redis命令能够很方便的执行队列操作了,但能做的可不止这些:比如Redis还有list pop的变体命令,能够在列表为空时阻塞队列。

    3.9  缓存

             我这里只是简单的说一下。Redis能够替代memcached,让你的缓存从只能存储数据变得能够更新数据,因此你不再需要每次都重新生成数据了。之后我会专门写一篇关于 redis做缓存的文章。

    转载请注明原文地址: https://ju.6miu.com/read-663272.html

    最新回复(0)