【Redis】Redis入门——分布式架构演进及Redis基本特性初识

目录

什么是Redis

Redis(Remote Dictionary Server,远程字典服务器)是一款开源、高性能、基于内存的键值对(Key-Value)数据库,核心特点是:内存存储 + 可选持久化,支持多种数据结构,兼具缓存、消息队列、分布式锁等多重功能,广泛用于高并发场景(如游戏服务器、电商秒杀、实时排行榜等)。

谈起数据库,我们可能最先想到的是MySQL,MySQL是一种基于外存的关系型数据库,诚然MySQL确实好用,功能也很强大,但是基于外存的原因让它的速度并不快(当然这里是说外存的硬件属性本身就是IO速度比较慢,限制了MySQL的发挥,MySQL已经在速度这一块做得很好了)。而Redis呢,他是基于内存的非关系型数据库,基于内存,这使得Redis的速度和MySQL相比是存在质的差别的,因为内存和外设的IO速度有指数级的差距。

那么我们应该直接无脑用Redis,直接抛弃MySQL了吗?当然不是。任何事物都是有利有弊的。MySQL基于外存,速度确实慢了,但是外存价格相对低廉,很便宜的成本可以买到相当大的存储空间。而Redis确实快,但是内存价格高昂,面对当今互联网洪水一般的数据,存储数据的要求连年增长的情况,用内存存下一切的想法根本不现实。

虽然有不少的互联网产品对性能要求很高,但是有更多的互联网产品对性能要求没那么高,Redis也好,MySQL也好,以及其他的一些数据库,都是要根据实际业务场景权衡利弊,来决定使用的。比如现实场景中,我们既想要大,又想要快,这时我们可以采用二八原则,即概率上来说20%的数据可以满足80%的访问需求,我们使用MySQL存储所有的数据,而后又根据算法提取出前20%的热点数据放到内存中用Redis缓存,这样既降低了成本,又提升了速度,但是这时又有Redis和MySQL之间的数据同步问题出现了,整个设计就又会变得更复杂,所以这就又印证了前面的话,任何事都是有利有弊,带来了一些好处,就会有一些坏处,世界总是不完美的。

当然我们说Redis是内存数据库,可能就会有人疑惑,内存存数据直接定义各种变量存不就行了,即存即用,为啥还要搞一个数据库呢?谈Redis,必谈分布式,如果只是单机架构,Redis确实没什么大作用,Redis在分布式系统中才能真正的大展拳脚。分布式简单来说就是将一个互应用切分成多个不同的模块,跑在多台主机上,那么这种情况下,数据直接存在内存中,进程和进程之间处于同一台主机也好,不是也好,都面临进程隔离性的问题,这时Redis通过最常见的进程通信的方式------网络,将自己内存的数据提供给其他进程来用。

分布式架构演进

分布式中的一些基本概念

应用(Application)/ 系统(System) :为了完成一整套服务的一个程序或者一组相互配合的程序群。
模块(Module)/ 组件(Component) :当应用较复杂时,为了分离职责,将其中具有清晰职责的、内聚性强的部分,抽象出概念,便于理解。比如一个电商网站可以切分出用户模块、商品模块、订单模块等。
分布式(Distributed) :系统中的多个模块被部署于不同服务器之上,即可以将该系统称为分布式系统。如 Web 服务器与数据库分别工作在不同的服务器上,或者多台Web服务器被分别部署在不同服务器上。
集群(Cluster):被部署于多台服务器上的、为了实现特定目标的一个/组特定的组件,整个整体被称为集群。比如多个MySQL工作在不同服务器上,共同提供数据库服务目标,可以被称为一组数据库集群。

分布式 vs 集群。通常不用太严格区分两者的细微概念,细究的话,分布式强调的是物理形态,即

工作在不同服务器上并且通过网络通信配合完成任务;而集群更在意逻辑形态,即是否为了完成特定

服务目标。

主(Master)/ 从(Slave) :集群中,通常有一个程序需要承担更多的职责,被称为主;其他承担附属职责的被称为从。比如MySQL 集群中,只有其中一台服务器上数据库允许进行数据的写入(增 / 删 / 改),其他数据库的数据修改全部要从这台数据库同步而来,则把那台数据库称为主库,其他数据库称为从库。
中间件(Middleware) :一类提供不同应用程序用于相互通信的软件,即处于不同技术、工具和数据库之间的桥梁。
可用性(Availability) :考察单位时间段内,系统可以正常提供服务的概率/期望。例如: 年化系统可用性 = 系统正常提供服务时长 / 一年总时长。这里暗含着一个指标,即如何评价系统提供无法是否正常,我们就不深入了。平时我们常说的 4 个 9 即系统可以提供 99.99% 的可用性,5 个 9 是 99.999% 的可用性,以此类推。我们平时只是用高可用(High Availability HA)这个非量化目标简要表达我们系统的追求。
响应时长(Response Time RT) :指用户完成输入到系统给出用户反应的时长。例如点外卖业务的响应时长 = 拿到外卖的时刻 - 完成点单的时刻。通常我们需要衡量的是最长响应时长、平均响应时长和中位数响应时长。这个指标原则上是越小越好,但很多情况下由于实现的限制,需要根据实际情况具体判断。
吞吐(Throughput)vs 并发(Concurrent):吞吐考察单位时间段内,系统可以成功处理的请求的数量。并发指系统同一时刻支持的请求最高量。例如一条辆车道高速公路,一分钟可以通过 20 辆车,则并发是 2,一分钟的吞吐量是 20。实践中,并发量往往无法直接获取,很多时候都是用极短的时间段(比如 1 秒)的吞吐量做代替。我们平时用高并发(Hight Concurrnet)这个非量化目标简要表达系统的追求。

架构演进

单机架构

一个最简单的业务系统,适合访问量少,对于性能安全要求不高的场景使用,架构简单,开发快速,成本低,只用部署在一台机器上。其实很多公司的服务,采用这种架构,就已经非常够用了,简单不代表垃圾,现在的硬件性能使得即使是一台服务器性能也不会很低的。

应用数据分离架构

当访问量逐步上升,用户量增大,对于性能安全有了一定的要求,预算也相对充足一些时,我们可以升级系统架构,将应用和数据分离。

和之前架构的主要区别在于将数据库服务独立部署在同一个数据中心的其他服务器上,应用服务通过网络访问数据。

应用服务集群架构

如果系统业务进一步增长,那么单机应用服务器就会遇到瓶颈,这事就由两种方案:

垂直扩展 / 纵向扩展 Scale Up :通过购买性能更优、价格更高的应用服务器来应对更多的流量。这种方案的优势在于完全不需要对系统软件做任何的调整;但劣势也很明显:硬件性能和价格的增长关系是非线性的,意味着选择性能2倍的硬件可能需要花费超过4倍的价格,其次硬件性能提升是有明显上限的。
水平扩展 / 横向扩展 Scale Out:通过调整软件架构,增加应用层硬件,将用户流量分担到不同的应用层服务器上,来提升系统的承载能力。这种方案的优势在于成本相对较低,并且提升的上限空间也很大。但劣势是带给系统更多的复杂性,需要技术团队有更丰富的经验。我们后续的架构演进其实就是以更少的成本引入更多的硬件资源以应对日益增长的用户、访问量、各种业务需求。

如果选择了水平扩展的方案,来解决该问题,但这需要引入一个新的组件------负载均衡 :为了解决用户流量向哪台应用服务器分发的问题,需要一个专门的系统组件做流量分发。实际中负载均衡不仅仅指的是工作在应用层的,甚至可能是其他的网络层之中。负载均衡器对于请求量的承担能力远超应用服务器,因为它不处理复杂业务逻辑,核心工作是核心工作是接收请求→根据算法分发请求,如果一台复杂均衡器承受不了,也可部署多台负载均衡器。同时流量调度算法也有很多种,这里简单介绍几种较为常见的:
Round-Robin 轮询算法 :即非常公平地将请求依次分给不同的应用服务器。
Weight-Round-Robin 轮询算法 :为不同的服务器(比如性能不同)赋予不同的权重(weight),能者多劳。
一致哈希散列算法 :通过计算用户的特征值(比如IP地址)得到哈希值,根据哈希结果做分发,优点是确保来自相同用户的请求总是被分给指定的服务器。也就是我们平时遇到的专项客户经理服务。

读写分离 / 主从分离架构

上一节提到,我们把用户的请求通过负载均衡分发到不同的应用服务器之后,可以并行处理了,并且可以随着业务的增长,可以动态扩张服务器的数量来缓解压力。但是现在的架构里,无论扩展多少台服务器,这些请求最终都会从数据库读写数据,到一定程度之后,数据的压力成为系统承载能力的瓶颈点。我们可以像扩展应用服务器一样扩展数据库服务器么?答案是否定的,因为数据库服务有其特殊性:如果将数据分散到各台服务器之后,数据的一致性将无法得到保障。所谓数据的一致性,此处是指:针对同一个系统,无论何时何地,我们都应该看到一个始终维持统一的数据。想象一下,银行管理的账户金额,如果收到一笔转账之后,一份数据库的数据修改了,但另外的数据库没有修改,则用户得到的存款金额将是错误的。

我们采用的解决办法是这样的,保留一个主要的数据库作为写入数据库,其他的数据库作为从属数据库。从库的所有数据全部来自主库的数据,经过同步后(MySQL有提供同步的机制),从库可以维护着与主库一致的数据。然后为了分担数据库的压力,我们可以将写数据请求全部交给主库处理,但读请求分散到各个从库中。由于大部分的系统中,读写请求都是不成比例的,例如100次读1次写,所以只要将读请求由各个从库分担之后,数据库的压力就没有那么大了。当然这个过程不是无代价的,主库到从库的数据同步其实是有时间成本的,但这个问题我们暂时不做进一步探讨。

引入缓存------冷热分离架构

随着访问量继续增加,发现业务中一些数据的读取频率远大于其他数据的读取频率。我们把这部分数据称为热点数据,与之相对应的是冷数据。针对热数据,为了提升其读取的响应时间,可以增加本地缓存,并在外部增加分布式缓存,缓存热门商品信息或热门商品的html页面等。通过缓存能把绝大多数请求在读写数据库前拦截掉,大大降低数据库压力。其中涉及的技术包括:使用memcached作为本地缓存,使用Redis作为分布式缓存,还会涉及缓存一致性、缓存穿透/击穿、缓存雪崩、热点数据集中失效等问题。

垂直分库

随着业务的数据量增大,大量的数据存储在同一个库中已经显得有些力不从心了,所以可以按照业务,将数据分别存储。比如针对评论数据,可按照商品ID进行hash,路由到对应的表中存储;针对支付记录,可按照小时创建表,每个小时表继续拆分为小表,使用用户ID或记录编号来路由数据。只要实时操作的表数据量足够小,请求能够足够均匀的分发到多台服务器上的小表,那数据库就能通过水平扩展的方式来提高性能。其中前面提到的Mycat也支持在大表拆分为小表情况下的访问控制。这种做法显著的增加了数据库运维的难度,对DBA的要求较高。数据库设计到这种结构时,已经可以称为分布式数据库,但是这只是一个逻辑的数据库整体,数据库里不同的组成部分是由不同的组件单独来实现的,如分库分表的管理和请求分发,由Mycat实现,SQL的解析由单机的数据库实现,读写分离可能由网关和消息队列来实现,查询结果的汇总可能由数据库接口层来实现等等,这种架构其实是MPP(大规模并行处理)架构的一类实现。

业务拆分------微服务

随着人员增加,业务发展,我们将业务分给不同的开发团队去维护,每个团队独立实现自己的微服务,然后互相之间对数据的直接访问进行隔离,可以利用 Gateway、消息总线等技术,实现相互之间的调用关联。甚至可以把一些类似用户管理、安全管理、数据采集等业务提成公共服务。

传统单服务架构中,一个服务程序承载所有业务逻辑,随着业务扩张,代码耦合度会持续上升,导致维护成本指数级增加;同时,团队规模扩大后,多人协作维护单服务的效率会大幅降低。基于此,微服务的核心思路是将复杂的单服务,拆分为功能单一、职责内聚的小型服务单元,并按服务功能进行团队分组管理(如用户服务组、订单服务组),通过拆分实现分工明确的协作模式。

拆分微服务并非无成本:微服务间的通信依赖网络调用,会引入额外的交互延迟;同时多服务部署需要更多硬件资源(服务器、存储等),直接提升了基础设施成本(引入万兆网卡)。服务数量的增加会放大故障概率(单个微服务的异常可能影响依赖链),需额外引入监控、容错、服务治理等机制,整体系统的运维复杂度显著提升。

微服务的核心优势在于解决 "业务与团队的规模化问题":解决多人协作的管理难题,按功能拆分的服务与团队分工一一对应,避免代码混乱;实现功能复用,独立的微服务可被多业务场景调用,减少重复开发;支持独立部署与迭代,不同服务可单独升级、扩容,提升业务迭代效率。

微服务并非通用方案:仅适用于业务复杂、团队规模较大的场景;小团队(如 3 人以内)采用单服务架构更高效。同时,当前硬件与网络性能的提升,已能有效抵消微服务带来的通信延迟问题,为其落地提供了技术支撑。

Redis基本特性

Redis是一个在内存中存储数据的中间件,可用作数据库,也能用作缓存,也可以用作消息队列(不常用,这是Redis的初衷,但是用的人却不多,因为有更好的选择)。

其在内存中存储数据,不是MySQL那种关系型数据库,而是非关系型数据库(NoSQL),使用键值对的方式存储数据。

我们可以用交互式命令操作Reedis,也能使用lua脚本语言批量执行一些操作。

Redis支持扩展(使用C / C++ / Rust),本质和动态库差不多。

因为Redis是基于内存存储,如果进程退出或系统重启那数据就没了,所以Redis会把数据存在硬盘上(内存为主,硬盘为辅,硬盘相当于备份),如果Redis重启,就会备份硬盘上的数据,使得Redis的内存恢复到重启之前的状态。

Redis也支持集群,一个Redis能存储的数据是有限的,引入多台主机,部署多个Redis节点,每个Redis存储数据的一部分。

Redis本身额也支持主从结构,从节点相当于主节点的备份了。

Redis为什么快?

内存存储:所有数据直接在内存中读写,避免了磁盘IO的延迟,这是性能优势的基础。

核心功能:Redis的核心功能都是相对比较简单的操作内存的数据结构。

单线程模型:核心网络IO与数据操作采用单线程,避免了多线程上下文切换的开销,同时通过IO多路复用技术(如 epoll)高效处理大量并发连接。

高效数据结构:底层采用哈希表、跳表等高效数据结构,结合紧凑的内存编码方式,减少内存占用的同时提升了读写效率。

C 语言实现:核心代码由C语言开发,底层性能损耗极低,进一步保障了执行效率。

相关推荐
無森~3 小时前
HBase概述、架构
数据库·架构·hbase
●VON3 小时前
Flutter for OpenHarmony:基于三层 Tab 架构与数据模型解耦的 TodoList 产品化演进
学习·flutter·架构·openharmony·布局·技术
SJLoveIT3 小时前
架构师视角:深度解构 Redis 底层数据结构的设计哲学
数据结构·数据库·redis
2401_840192273 小时前
ZooKeeper 集群部署指南(Kubernetes StatefulSet 方式)
分布式·zookeeper·kubernetes
Loo国昌3 小时前
【LangChain1.0】第十四阶段:Agent最佳设计模式与生产实践
人工智能·后端·算法·语言模型·架构
晚霞的不甘3 小时前
Flutter for OpenHarmony:迈向专业:购物APP的架构演进与未来蓝图
其他·flutter·架构·fiddler·前端框架·harmonyos
Anastasiozzzz3 小时前
RabbitMQ介绍与基础架构
分布式·rabbitmq
万岳科技系统开发3 小时前
配送外卖系统源码整体架构解析:从下单到配送的技术实现
架构
【赫兹威客】浩哥3 小时前
【赫兹威客】完全分布式HBase测试教程
数据库·分布式·hbase