文章目录
认识redis(1)
什么是redis?redis干啥用的?
Redis的全称:Remote Dictionary Server,远程字典服务
Redis是一个开源的内存数据结构存储系统,也就是说Redis是用来存数据的!
Redis的初心是用来作为一个“消息中间件”(消息队列),处理分布式系统下的生产者消费者模型的 ,但是后来人发现Redis做分布式下的数据库和存储系统会更香,有意栽花花不开,无心插柳柳成荫了属于是
什么情况下要用redis存数据?
那问题就来了,我正常在C语言中定义个变量,系统都会自动从内存中为我分配空间,我干嘛还要用你redis啊?
如果只是单机程序,直接通过变量存储数据的方式,是比使用 Redis 更优的选择
但是如果在分布式系统中,用Redis存储数据才是更优的选择
Redis 可以通过网络把自己内存中的变量给别的进程,甚至别的主机的进程进行使用
mysql和redis的比较
(1)存储数据的形式
MySQL 主要是通过“表”的方式来存储组织数据的“关系型数据库”
Redis 主要是通过“键值对”的方式来存储组织数据的“非关系型数据库”
(2)速度
redis比mysql快(redis用的存储器是快速缓存,mysql用的存储器是硬盘)
(3)存储空间和功能
mysql的存储空间比redis大很多,mysql提供的功能也比redis要多不少
从上面我们可以看到,虽然MYSQL容量大,功能全面,但是速度慢,虽然redis速度快,但它容量小。既然如此,那有没有存储量还大速度还快的方案呢?
当然有,把Redis和MySQL结合起来使用,让Redis作为Cache,MySQL作为主存 ,采用这样的方案存储,就是存的还大
认识分布式
Redis和分布式这俩词可以说是深度绑定的,因为Redis的应用场景就是分布式系统,Redis在分布式系统扮演着Cache的角色。因此我们要先认识一下分布式
为什么要搞分布式系统?
一个服务器的软件业务可以越做越复杂,但随着软件越来越复杂,对硬件的要求也会越来越高,比如需要更快的CPU算力来处理海量请求,需要更大的存储空间存储数据等等。
但是以目前的技术来说,一台主机中的硬件资源是有极限的,根本无法赶上软件业务膨胀的速度,于是我们才想多加几台主机,在硬件层面上实现开源。
总的来说,我们之所以引入分布式系统,就是想要为一个系统引入更多的硬件资源!(CPU、内存、硬盘、网络)
而分布式又是为了解决单机架构的请求处理瓶颈才提出的概念,所以我们还要先了解一下什么是单机架构
什么是单机架构?
单机架构就是你的服务只有一台服务器,所有的服务都由这台服务器负责
比如你在网页中下了一个订单,web就会发给服务器,服务器接收到请求之后,对你的请求做一定的处理,把你刚刚下的订单信息添加到数据库(订单队列)中
单机架构的服务器,同时处理几万条请求还是绰绰有余的,千万不要瞧不上这个东西。绝大部分的公司的产品,都是这种单机架构!!!现在计算机硬件,发展速度非常之快~~ 哪怕只有一台主机,这一台主机的性能也是很高的. 可以支持非常高的并发和非常大的数据存储.
但如果业务进一步增长,用户量和数据量都水涨船高,一台主机难以应付的时候,就需要引入更多的主机,引入更多的硬件资源
为什么用户量和数据量多了,一台主机就难以应付呢?
原因就是:一台主机的硬件资源是有上限的!!!
一台主机有哪些硬件资源呢?
一台主机的硬件资源单包括不限于以下几种:
CPU、内存、硬盘、网络
服务器每次收到一个请求,都是需要消耗上述的一些资源
如果同一时刻,处理的请求多了,此时就可能会导致某个硬件资源,不够用了!!!
无论是哪个方面不够用了,都可能会导致服务器处理请求的时间变长(木桶效应)~甚至于处理出错~~
如果服务器主机不够用,我们应该怎么处理呢?
1. 简单粗暴,增加更多的硬件资源
但是!一个主机上面能增加的硬件资源也是有限的!具体能增加多少具体取决于主板的扩展能力。如果一台主机扩展到极限了,但是还不够!那就只能引入多台主机了!!!
并且也不是说新的机器买来就直接可以解决问题,引入新硬件之后,我们也需要在软件上做出对应的调整和适配,才能正常使用这些新加的硬件。一旦引入多台主机了,咱们的系统就可以称为是 “分布式系统”了!
而引入分布式,这是万不得已的无奈之举!这是为啥呢?虽然分布式系统确实能给服务器扩充更多的硬件资源,但是凡事都是有代价的,你多台主机管起来,肯定比管理一台主机要费事的多!即引入分布式之后:
=> 系统的复杂程度会大大提高
=> 出现 bug 的概率提高
=> 加班的概率 & 丢失年终奖的概率 随之提高~~
2. 软件上优化
这个就各凭本事了,需要程序员通过性能测试,找到是哪个环节出现了瓶颈,再去对症下药。对于程序猿的水平要求比较高!
什么是分布式架构?
下面我们就从分布式架构的演化过程的角度,来看看到底什么是分布式架构
分布式架构的演化过程
最开始的单机架构
在最开始的单机架构中,服务器部署在一台主机上,这台主机不仅要负责处理用户的请求,还需要存储对应的数据库
扩展应用服务器
由于应用服务可能会比较吃 CPU 和 内存,如果我们将应用服务与存储服务部署在同一台主机中,当前主机的资源可能不太够用。所以我们可以尝试将服务器中任务处理和数据存储的功能相分离,将应用服务部署在一台主机,将存储服务部署在另一台主机中。部署应用服务的那台机子,我们就叫他应用服务器,部署存储服务的那台机子,我们就叫他存储服务器
如果我们的应用服务比较复杂,或者发起请求的用户比较多,可能一台应用服务器也不太够用,因此我们还可以多加几台,然后在服务器的上层再加一个负载均衡器,负责将多条用户请求均衡地平摊到每台应用服务器中
引入负载均衡器和多台应用服务器之后,用户发起的请求会先到达负载均衡器/网关服务器~(独立的服务器),然后负载均衡器将请求以某种策略分发给下面的各个应用服务器。
假设有 1w 个用户请求,有 2 个应用服务器.此时按照负载均衡的方式,就可以让每个应用承担 5k 的访问量~~ ,这就减少了每个应用服务器的工作压力
来自世界各地的请求都会先发往这个负载均衡器,这个东西能顶住嘛??
负载均衡器只负责分配任务,不负责具体任务的执行,所以负载均衡器,对于请求量的承担能力,要远超过应用服务器的。
举个生活中的例子,
负载均衡器,就相当于领导,上级给他安排的任务很多,但是他并不负责具体干这个活,而是负责把这些活派给下面的员工干
应用服务器,就相当于是员工,负责具体干活
是否可能会出现,请求量大到负载均衡器也扛不住了呢?
也是有可能的!!!解决方案就是引入更多的负载均衡器~~ (引入多个机房)
举个例子
扩展存储服务器
在前面讨论的过程中,系统的应用服务器越来越多,但是存储服务器还是只有一个,应用服务器在处理请求的时候,对于那些对数据库的CRUD操作,是需要交给存储服务器来处理的。如果所有请求的CURD操作都交给同一个存储服务器来完成,那他压力太大崩掉了咋办?所以我们要也要对存储服务器的架构进行优化
存储服务器架构优化的方式同样是开源 + 节流(门槛高,更复杂) 。其中节流是要从软件层面优化服务器内部的处理技术,门槛高,更复杂,我们不做过多讨论,下面我们主要就介绍,通过开源——也就是增加存储服务器的方式,来减少每个服务器的压力
对于增加存储服务器,我们首先采用一主多从的架构,就是一个主服务器专门用来处理对数据库的写操作,其余服务器都只处理对数据库的读请求
数据库天然有个问题,由于数据库的存储设备是固态硬盘,对数据库进行读取操作时,他的响应速度是很慢的!对于这个问题我们如何改进呢?
我们参照计组中存储器cache+主存的体系结构,把数据区分 “冷热”,将数据库中经常被读取的数据复制一份,拷贝到服务器的缓存中(热点数据放到缓存中),一般的数据就只放在服务器的固态硬盘中,这样读取速度就快很多了!!
既然缓存很快,为什么不把所有数据都放到缓存中呢?
想要达到某种效果,一定要付出某种代价
缓存确实很快,但是付出的代价就是,缓存的容量很小,没办法所有数据都放到缓存中
我们都知道,手机上网的一大功能就是看视频,视频的大小可比图片和文字大多了,那么多的视频集合到一个数据库中,一个服务器肯定放不下,这时候我们应该如何处理?
如果一个存储服务器放不下这么多数据,我们就引入多个数据库服务器. 每个数据库服务器存储一个或者一部分数据库~
如果某个表特别大,大到一台主机存不下, 也可以针对表进行拆分,即一个服务器存某张表的一部分
举个例子,假如我们的存储服务器中有多个数据库,一个服务器存不下,那我们就采用下图中的存储集群架构,每个数据库用都分别用一个存储集群来存。一个集群又由一个主数据库和若干个从数据库组成,其中一个主数据库用来存数据目录,其余数据库用来存具体的数据
最终的分布式架构
到此我们就得到了最终的分布式架构
采用这样的分布式架构,系统的存储能力与业务处理能力都会得到显著的提高,既然如此,我们付出的代价又是什么呢?
当人变多了,管理成本就会提高,出现问题的概率也会提高。当机器变多了,管理成本也会提高~~ 出现问题的概率也会提高。 复杂的分布式架构,在提升性能的同时,也提高了对于数据库管理技术的要求。系统越复杂,就越容易出现问题,问题出现之后也越难解决
分布式系统演变小结
前面我们只是从扩展应用和存储服务器的角度展示了分布式系统大概的演变过程,其中还忽略了一些细节,下面是一个更详细的演变过程
单机架构 (应用程序 + 数据库服务器)
数据库和应用分离
应用程序和数据库服务器 分别放到不同主机上部署了.引入负载均衡, 应用服务器 => 集群
通过负载均衡器, 把请求比较均匀的分发给集群中的每个应用服务器.
当集群中的某个主机挂了, 其他的主机仍然可以承担服务,提高了整个系统的可用性引入读写分离, 数据库主从结构
一个数据库节点作为主节点, 其他N个数据库节点作为从节点. 主节点负责 写 数据. 从节点负责 读 数据. 主节点需要把修改过的数据同步给从节点~引入缓存, 冷热数据分离
进一步的提升了服务器针对请求的处理能力.
Redis 在一个分布式系统中, 通常就扮演着 缓存这样的角色~~
二八原则
引入的问题: 数据库和缓存的数据一致性问题(如何同步数据库和缓存中的数据?)引入分库分表, 数据库能够进一步扩展存储空间
引入微服务,从业务上进一步拆分应用服务器
从业务功能的角度,把应用服务器,拆分成更多的功能更单一,更简单,更小的服务器。
上述这样的几个演化的步骤,只是一个粗略的过程。 实际上一个商业项目,真实的演化过程,都是和他的业务发展密切相关的。 业务是更重要的,技术只是给业务提供支持的。
之所以要搞分布式系统,最终目的就是想办法为一个系统引入更多的硬件资源!
微服务架构
什么是微服务架构?
对于一个应用服务器来说,如果服务器程序里面做了很多的业务。这就可能会导致这一个服务的代码变的越来越复杂~
为了更方便于代码的维护,我们就可以把这样的一个复杂的服务,拆分成若干个功能更简单,但是更小的服务(微服务)。
什么时候需要用到微服务?
当应用服务器复杂了,才需要更多的人来维护。如果是小公司,就两三个开发~此时搞微服务就没有太大必要了
划分微服务带来的好处是什么?
首先是我们最容易想到的好处
1. 方便维护
微服务的代码量要显著少于之前的服务,更方便维护
2. 低耦合的特点使得服务迭代起来更加方便
比如我只想更新音乐模块,就只需要更新音乐微服务的代码,其他模块的代码根本不用动
3. 便于管理和追责
一个复杂的服务器,需要配套的研发人员也是很多的,人多了,就不好管理。通过微服务的划分,可以方便我们更好地对一个复杂项目中的人员进行管理(比如追责的时候,划分的越精细,追责的人越具体)
4. 更方便功能的复用
可能另一个项目中会用到你这个服务器提供的某一个功能
如果你不划分微服务,光对外暴露一个整体功能的接口,那对面就不好调用
如果你划分了微服务,把里面一个个小的功能函数接口都暴露出来,那对面就好调用了
5. 更充分地利用硬件资源
- 假如说你这一个复杂服务器,里面有一些函数功能实现起来比较简单,有一些功能实现起来就比较复杂。
- 如果不划分微服务器,很有可能出现一种现象,就是我机子的性能介于这两种任务之间
- 跑A函数,性能浪费了,跑B函数,性能不够
- 这时候如果我们划分了微服务器,那么我给A功能配一个性能比较差的机子,给B功能配一个性能比较好的机子,现在这俩都合适了
提供微服务付出的代价是什么?
1. 系统性能下降(运行速度下降)
一个服务器拆出来更多的微服务器,多个功能之间要更依赖 网络通信.,网络通信的速度可是比硬盘还慢的啊!!!
幸运的是,硬件技术的发展,网卡现在有 万兆 网卡。读写速度已经能超过硬盘读写了~~但是它贵啊!!一般只有大公司才买得起
要想保证性能不下降太多,只能引入更多的机器,更多的硬件资源 => 充钱~~
2.系统复杂程度变高,出错概率提高,DEBUG更加困难
服务器更多了,出现问题的概率就更大了~~
这就需要一系列的手段,来保证系统的可用性~~
(更丰富的监控报警,以及配套的运维人员)
认识redis(2)
Redis 是一个在内存中存储数据的中间件。用于作为数据库和数据缓存,在分布式系统中能够大展拳脚~
redis作为数据库最大的优势是什么?
redis快!
redis为什么比mysql快?(面试高频考点)
(1)redis的存储器是内存,MYSQL用的是磁盘
快慢都是对比出来的,我们说redis快,主要是相对于mysql来说的
Redis 数据在内存中。就比访问硬盘的mysql,要快很多~~
Redis的存储器用的是内存条,mysql的存储器用的是硬盘
Redis访问内存,mysql访问硬盘
(2)redis指令逻辑比较简单,mysql比较复杂
Redis 核心功能都是比较简单的逻辑~~Redis核心功能比mysql简单
数据库对于数据的插入删除查询…都有更复杂的功能支持。这样的功能势必要花费更多的开销。比如,针对插入删除,数据库中的各种约束,都会使数据库做额外的工作。
redis干的活少。提供的功能相比于mysql也是少了不少
(3)Redis 使用了 单线程+IO多路复用的方式 ,而MYSQL用的是多线程
多线程的缺点:
- 线程越多,线程间切换的时间成本就越高,这些时间对于效率提升是没有任何作用的
- 多线程访问数据库时,为了保证数据库的一致性,很多操作都需要加锁,一旦加锁,就将并行操作串行化,这就与单线程速度差不多了
根据上述描述我们可以看到,多线程并发访问数据库,由于很多操作要加锁。因此相比单线程访问带来的速度提升并不明显,同时多线程之间彼此切换,还需要有额外的时间开销,因此数据库服务器用单线程加多路转接的方式无疑是更好的选择
Redis 可以用于作为数据库,那Redis中组织数据的方式是什么?redis是关系型数据库吗?
MySQL 主要是通过“表”的方式来存储组织数据的“关系型数据库”
Redis 主要是通过“键值对”的方式来存储组织数据的“非关系型数据库”(什么是键值对?)
键值对即<key , value>,其中key的类型只能是string,value的类型就比较多了,这里不再列举
Redis的应用场景是什么?
(1)把 redis 当做一个比mysql更快的数据库(比较烧钱)
大多数情况下,考虑到数据存储,优先考虑的是“大”
但是仍然有一些场景,考虑的是“快”
比如做搜索引擎 :广告搜索(商业搜索),这种对性能要求非常高的项目不可能MySQL这样的数据库(因为太慢了)
项目需要把所有需要检索的数据都存储在内存中,就使用的是类似于 Redis 这样的内存数据库来完成的。当然,使用这样的内存数据库,存储大量的数据,需要不少的硬件资源的。(即把 redis 当做一个比mysql更快的数据库是比较费钱的!)
注意:这里Redis 存的是全量数据。里面存的数据是不能随便丢的
(2)把redis当做是mysql的Cache,将mysql中的热点数据存到Redis中,这样Redis+mysql的存储系统就又大又快了
使用 MySQL 存数据,虽然容量大,但是操作比较慢。
根据二八原则,我们把热点数据拎出来,存储在 redis 中
Redis 存的是部分数据。全量数据都是以 mysql 为主的。哪怕 Redis 的数据没了,还可以从 mysql 这边再加载回来~~
(3)把redis当做一个消息队列(Redis的初心)
Redis作为消息队列有以下作用:
解耦生产者和消费者
在一个电商系统中,订单创建是生产者,库存更新、物流通知等是消费者。订单创建后只需把消息发到Redis消息队列,不用关心后续库存怎么减、物流通知怎么发 。库存系统和物流系统从队列拉取消息处理,彼此逻辑分离。这样若新增功能(如增加优惠券核销),在队列添加对应消费者即可,不会影响订单创建等其他功能,提高了系统灵活性与可扩展性。
实现异步处理
以一个内容发布系统为例,用户发布文章(生产者操作),系统要进行内容审核、生成索引、推送给关注者等操作(消费者操作)。若同步处理,用户需等所有操作完成才知道发布成功,体验差且系统并发低。用Redis消息队列,用户发布后消息入队就返回,后续审核、索引生成等操作异步进行,提高了系统响应速度和并发处理能力 。
削峰填谷
在电商大促(如双11)时,瞬间大量下单请求并发。若直接处理,数据库等后端服务可能因压力过大崩溃。Redis消息队列可在流量激增时缓存请求,系统按自身处理能力从队列消费消息,如每秒处理1000个订单,即使瞬间涌入10万个订单,也可在队列中暂存,随着时间推移慢慢处理完,保证系统在高并发下稳定运行 。
支持分布式系统
在分布式架构的大型互联网应用中,不同服务部署在不同服务器。Redis支持分布式部署,其消息队列能实现分布式事务和分布式锁等功能。比如多个服务共同完成一个业务流程,通过消息队列协调,保证操作按顺序执行,满足复杂分布式系统的需求 。
实现实时消息推送
利用Redis的Pub/Sub功能,可构建实时消息推送系统。像直播平台,主播发布直播(生产者发布消息),订阅该频道的观众(消费者)能实时收到开播通知,实现实时互动 。
Redis不适合干什么事儿?(不适用redis的场景)
Redis不适合存储大规模数据
分布式系统如何适配cookie和session技术?
cookie和session原理
如果是单机架构的服务器,每次用户注册时,服务器端会将该用户的注册信息备份到数据库中,并给该用户分配一个session id ,浏览器收到响应报文时,将seeion id存入cookie中,下次再向该服务器发送请求时,请求报文就携带上这个cookie,服务器端检测时一看,就会把这个session id对应的数据取出来,就认得这个用户了
分布式系统中,cookie和session技术遇到的问题
如上图所示,用户注册时,服务器为其生成了session信息并保存在了第一台服务器中,分布式系统会进行负载均衡,所以下次该用户再请求的时候,可能该请求会被分配到第二台服务器,但是第二台服务器上没有该用户对应的session啊,这不就没办法解决了吗?
如何解决上述问题呢?
想办法让负载均衡器,把同一个用户的请求始终打到同一个机器上
如果这样做的话,就不能轮询了,而是要通过 userid 之类的方式来分配机器将session信息保存在redis中
把会话数据单独拎出来,放到一组独立的机器上存储(Redis)
(应用程序重启了,会话不丢失)