除了缓存之外,Redis还有哪些问题需要解决?

发布者:上海IT外包来源:http://www.lanmon.net点击数:1259

目录:
1从零开始
2基于本机内存缓存
3服务器端Redis
3.1持久性
3.2 Sentinel和复制
3.3集群(集群)
4客户Redis
4.1数据类型
4.2交易
4.3 Lua脚本
4.4管道
4.5分布式锁
总结一下
我们来看看Redis是什么。官方介绍解释:Redis是一个基于BSD的开源项目。它是一种将结构化数据放入内存的存储系统。您可以将其用作数据库,缓存和消息中间件。它还支持数据类型,如字符串,列表,散列,集合,有序集,位图,超级日志和地理空间索引。它还具有内置功能,如复制,lua脚本,LRU,事务等,通过redis sentinel实现高可用性,以及通过redis集群自动分段。以及事务,发布/订阅,自动故障转移等。
除了缓存之外,Redis还有哪些问题需要解决?
总之,Redis提供了丰富的功能,首次出现时可能会令人眼花缭乱。这些功能使用了什么?哪些问题已经解决了?在什么情况下会使用相应的功能?然后以下是零。开始,一步一步演变为粗略的解释。
1从零开始
最初的要求非常简单。我们有一个提供热门新闻列表的API:http://api.xxx.com/hot-news,api消费者抱怨每个请求大约需要2秒才能返回结果。
然后我们阐述了如何提高api消费者所感知的性能。很快就出现了最简单,最粗鲁的第一个解决方案:对于API的响应以及基于HTTP的缓存控制缓存控制: max-age=600,即让消费者将此响应缓存十分钟。如果api消费者有效地利用响应中的缓存控制信息,它可以有效地改善其感知性能(在10分钟内)。但是有两个缺点:第一个缺点是在缓存有效的10分钟内,api消费者可能获得旧数据;第二个是如果api客户端忽略缓存并直接访问API,它仍然需要2秒。它无法解决问题。2基于本机内存缓存
为了解决调用API的问题,它仍然需要2秒。排除故障后,主要原因是使用SQL获取热门新闻需要将近2秒钟。因此,我们想到了一个简单而粗鲁的解决方案,即SQL查询的结果直接缓存在当前api服务器的内存中(将缓存有效时间设置为1分钟)。 1分钟内的请求直接读取缓存,执行SQL所需的时间不超过2秒。如果api每秒收到100个请求,则一分钟为6000,也就是说,只有拥挤请求的前2秒需要2秒,即使响应没有等待2秒,也可以在58秒内完成所有后续请求。
其他API合作伙伴发现这是一个好主意,因此我们很快发现API服务器的内存已满。 。 。
3服务器端Redis
当API服务器的内存充满缓存时,我们发现我们必须考虑一个解决方案。最直接的想法是我们将所有这些缓存都放在专用服务器上并将其内存配置放大。然后我们盯着redis。 。 。至于如何配置redis的部署,这里没有解释。 redis官员有详细的介绍。然后我们使用单独的服务器作为Redis服务器,并解决了API服务器的内存压力。
3.1持久性
单个Redis服务器每月有几天心情不好。如果你心情不好,它会打击,导致所有缓存都丢失(redis数据存储在内存中)。虽然Redis服务器可以重新上线,但由于内存数据丢失,缓存雪崩,API服务器和数据库压力仍在不断上升。所以此时Redis的持久性功能派上用场,可以缓解缓存雪崩的影响。 Redis持久性意味着redis将内存中的数据写入硬盘并在redis重新启动时加载数据,从而最大限度地减少缓存未命中的影响。
3.2 Sentinel和复制
Redis服务器在没有警告的情况下罢工是一件麻烦事。所以我该怎么做?答:备份一个,你把它挂起来。那么你怎么知道redis服务器挂起,如何切换,如何确保备份机器是原始服务器的完整备份?这次需要出现Sentinel和Replication。 Sentinel可以管理多个Redis服务器,提供监控,警报和自动故障转移;复制是负责让一台Redis服务器具有多个备份的服务器。 Redis还使用这两个功能来确保Redis具有高可用性。此外,Sentinel功能还使用了Redis的发布和订阅功能。3.3集群(集群)
单个服务器的资源总是有限制的。主从可以复制和读取CPU资源和IO资源,并且一些CPU和IO压力被传输到从属服务器。但是如何做内存资源,主从模式只是备份相同的数据,而不能横向扩展内存;一台机器的内存只能增加,但总有一个限制。所以我们需要一个允许我们扩展的解决方案。最终目标是仅为每个服务器的一部分处理它,以便所有这些服务器形成一个整体。对于外部世界,这组分布式服务器就像一个集中式服务器(之前的REST博客解释解释了基于网络的分布式差异:基于Web应用程序的架构)。
在Redis官方分发解决方案问世之前,有两个方案,twemproxy和codis。这两个方案都依赖于分布式代理,这意味着redis本身并不关心分布式事物,而是依赖于twemproxy和codis。 Redis提供的集群解决方案正式实现了Redis服务器的这个分布式部分,因此它可以独立完成分布式需求,而无需其他组件。我们不关心这些解决方案的优势。让我们关注这里的分布。 twemproxy和codis独立处理的是什么?这部分逻辑和集群集成到Redis服务中。什么问题正在解决?
正如我们之前所说,分布式服务看起来像是对外部世界的集中服务。所以要做到这一点,有一个问题需要解决:增加或减少分布式服务中的服务器数量,它应该对消费服务的客户端无感;然后它意味着客户端您无法穿透分布式服务并将自己绑定到其中一台服务器上的服务器,因为一旦您这样做,就无法再添加服务器,也无法替换它们。有两种方法可以解决这个问题:第一种方式是最直接的,也就是说,我添加了一个中间层来隔离这个特定的依赖关系,即twemproxy采用的方式,这样所有的客户端只能通过redsi服务来使用它。使用它来隔离这种依赖关系(但你会发现twermproxy将成为一个单点),在这种情况下每个redis服务器是独立的,他们不知道彼此的存在;第二种方法是让redis服务器了解彼此的存在,通过重定向机制引导客户端完成他们需要的操作,比如客户端链接到redis服务器,说我要执行这个操作, redis服务器发现它无法完成操作,然后将可以执行此操作的服务器的信息发送到客户端,并让客户端请求另一台服务器。此时,您会发现每个redis服务器都需要维护有关分布式服务器信息的完整信息。否则,它如何知道让客户端找到哪个其他服务器来执行客户端想要的操作?它。以上段落解释了这么多。我想知道是否存在共同点,无论是第一种方式还是第二种方式,即分布式服务中的所有服务器以及它们可以提供的信息。 。这个信息无论如何都必须存在,区别在于第一种方式是分别管理这部分信息,利用这些信息来协调后端多个独立的红色镜头服务器;第二种方法是让每个redis服务器保存这些信息并了解彼此的存在以实现与第一个相同的目的,优点是不需要额外的组件来处理这部分问题。
Redis Cluster的具体实现细节采用Hash槽的概念,即预先分配16384个槽:客户端的CRC16(key)%16384操作用于获取相应的槽位;在redis服务器上,每个服务器负责插槽的一部分。添加或删除新服务器时,将迁移插槽及其相应的数据。每个服务器保存完整的插槽及其对应的服务器信息。准则服务器端可以发送请求发送到CL。
4客户Redis
上面的第三部分重点介绍了Redis服务器的演进步骤,解释了Redis如何从独立服务演变为高度可用,分散的分布式存储系统。本节重点介绍客户端可以使用的redis服务。
4.1数据类型
Redis支持各种数据类型,从最基本的字符串到复杂的常用数据结构:
String:最基本的数据类型,二进制安全字符串,最大512M。
列表:按添加顺序保存的字符串列表。
Set:无序的字符串集合,没有重复的元素。
排序集:排序字符串的集合。
哈希:键值对的集合。
位图:更精细的操作,以位为单位。
Hyperloglog:基于概率的数据结构。
这些很多数据类型主要是为了支持各种场景的需求,当然每种类型都有不同的时间复杂度。事实上,这些复杂的数据结构等同于我在《解读REST》系列博客中基于Web应用程序的架构风格引入的远程数据访问(远程数据访问=RDA),即通过执行一组服务器上的标准。操作命令在服务器之间获得所需的缩减结果集,简化了客户端的使用并提高了网络性能。例如,如果没有列表等数据结构,则只能将列表保存为字符串。客户端获取完整列表,然后在操作后将其完全提交给redis,这将导致大量浪费。4.2交易
上述每种数据类型都有一个独立的操作命令。在许多情况下,我们需要一次执行多个命令,并且它需要同时成功或失败。 Redis对事务的支持也源于这一部分要求,即支持在单个命令中执行多个命令并保证其原子性的能力。
4.3 Lua脚本
在事务的基础上,如果我们需要在服务器端执行更复杂的操作(包括一些逻辑判断),lua可以派上用场(例如,在获取缓存时,并延长其到期时间))。 Redis保证了lua脚本的原子性。在某些情况下,它可以替换redis提供的与事务相关的命令。这相当于基于网络应用程序在架构风格中引入的远程评估(Remote Evluation=REV)的实现。
4.4管道
由于Redis的客户端和服务器连接是基于TCP的,因此默认情况下每个连接只能执行一个命令。管道允许使用一个连接处理多个连接,从而节省了一些tcp连接开销。管道和事务之间的区别在于管道旨在节省通信开销,但它们不保证原子性。
4.5分布式锁
官方建议使用Redlock算法,即使用字符串类型,锁定时给出一个特定的键,然后设置一个随机值;取消锁定时,首先使用lua脚本执行比较,然后删除密钥。具体命令如下:
SET resource_name my_random_value NX PX 30000
如果redis.call('get',KEYS [1])==ARGV [1]那么
返回redis.call('del',KEYS [1])
其他
返回0
结束
总结一下
本文重点介绍了redis功能的抽象及其存在的目的,而没有注意其具体细节。因此,我们可以专注于它解决的问题。根据抽象层次概念,我们可以在特定场景中选择更合适的解决方案,而不是仅限于其技术细节。
IT外包
>
400-635-8089
立即
咨询
电话咨询
服务热线
400-635-8089
微信咨询
微信咨询
微信咨询
公众号
公众号
公众号
返回顶部