(一)认识redis
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
起初redis是用来作为一个“消息队列”的,简单理解就是在分布式系统下的生产者消费者模型,但是随着计算机的发展,我们很少会直接使用redis作为消息队列,反而用redis来做一些其他的事情,比如数据库。
那之前我们学到的mysql和redis哪一个更合适我们?这里我们要先了解,redis存储数据是在内存中存储的,这就使得我们访问速度比较快,而mysql的数据是在硬盘上存储的,这就会导致我们的访问速度比较慢。但是内存空间是有限的,虽然硬盘空间也有限,但是相比内存还是大了不少。
所以在对于性能要求比较高的情况下,我们可以选择redis,在对性能要求不高的情况下可以使用mysql。我们也可以结合redis和mysql,我们可以将需要频繁访问的数据放到redis中,其他数据放到mysql中,这样就可以解决内存不够大,且效率低的问题,但是凡事有两面性,这样会导致系统的复杂程度提升,如果数据发生修改还会涉及到redis和mysql的数据同步问题。
这时我们就会有疑问?在内存中存储数据,但我们定义变量不也是在内存中存储的吗?为什么要使用redis,这时因为进程有隔离性,进程间的通信需要基于网络,而redis就可以通过网络将自己内存中的变量给其他进程甚至主机使用(也就是分布式系统中),如果知识单机单进程,那我们完全没有必要使用redis。
(二)分布式系统的演化过程
上述我们说了redis广泛应用于分布式系统上,那什么是分布式系统,我们来看一下他的演化过程
1.单机架构
只有一台服务器,这个服务器会处理所有的请求,服务器中分为两个模块一个用来处理应用服务,一个用来处理数据库服务,我们也可以划分成一个模块,由着一个模块来处理业务和数据。
其实我们大部分公司需求量没有那么大,我们现有的计算机资源即使一台主机也足够应对大部分情况,可以支持很高的并发和数据存储。
2.使用分布式系统
但是随着业务增长,一台主机可能难以应对如此高的并发请求,所以这时候我们可以引入更多的主机和硬件资源来解决这个问题。
一台主机的资源包括很多比如:CPU.内存,硬盘,网络等等,服务器每收到一个请求都会消耗一定的资源,如果在高并发的情况下,我们的服务器无法支持这么多请求,就会导致服务器处理请求的速度变慢,甚至发生错误。
那我们可以通过两种方法来解决:
1.开源:引入更多资源(增加服务器,更换cpu,加内存条等等)
2.节流:通过性能测试,找到那个地方效率不高,进行优化(比较难,需要投入很多的人力物力,也不一定能优化多少)
所以我们还是想通过开源的方式来解决服务器压力过大的场景,但是我们装过机的应该知道,电脑主板的内存条是有限的,不仅是内存条,其他资源也是有上限的,那一台主机扩展到极限,我们就需要引入多台主机,并且在软件上做出对应的调整和适配就可以解决上述服务器压力大的问题,而这种通过引入多台主机的系统方式,就可以称为分布式系统。
这时我们可以将应用服务和数据库服务进行分离,根据内部业务的不同加强各自的硬件资源
比如应用服务器需要处理很多业务逻辑,我们就可以加强他的cpu资源,数据库服务器需要存储大量数据,就可以增加他的硬盘空间
3.应用服务集群架构
如果我们应用服务器的负载仍然很高,我们就需要在引入多个应用服务器,同时引入一个负载均衡,通过一个负载均衡将业务分给多个应用服务器,假设1w个用户请求,有2个应用服务器,此时按照负载均衡的方式,就可以让每个应用服务器来承担5000的访问量(这个事情和之前的多线程有些类似)。
上述我们增加了应用服务器,但是所有数据还是要经过负载均衡器,那我们负载均衡器能不能承受住这么多数据?
实际上负载均衡器对于请求量的承担能力要远高于应用服务器的,因为负载均衡器只是给应用服务器分配业务,并没有对数据进行处理,而且就算一个负载均衡器不够用,我们也可以引入多个。
但除了负载均衡器,上图也只有一个存储服务器,那我们该如何解决呢?我们仍然可以使用开源,节流的方法,但在这里我们可以根据服务器的特性(存储服务器)来进行划分,我们可以将读写进行分离
我们将存储服务器分为主服务器和多个从服务器,主服务器一般只有一个,从服务器可以有多个,主服务器用来向服务器进行写操作,从服务器数据同步主服务器,应用服务器访问时,可以更多的从从服务器中读取数据
4.引入缓存服务器(redis)
mysql数据库最大的问题就是响应速度慢,所以我们可以将数据划分成两部分,一部分是高频使用的一般占20%,但是却能满足我们80%的数据需求,一部分是低频使用的大约占总数据的80%(我们称为28原则),我们可以将高频使用的数据放到缓存中,因为缓存的访问速度对比数据库要快很多
那为什么要二八分呢,其实也不绝对,根据实际场景和业务的不同,会有差异,而之所以只占20%就是因为缓存虽然快,但是太小了。
上述我们说,服务器负载过大我们可以引入从服务器来帮主服务器实现读写分离降低负载,那如果服务器的内存不够用了该怎么办?这时我们就可以引入多台主机,每个主机存储一些数据,也就是针对之前的数据库进行拆分(分库分表)
5.微服务架构
之前一个应用服务器做了很多业务,但是这会导致服务器的代码越来越复杂,所以我们可以将这样的服务器功能进行拆分变成更小的服务器
那我们为什么要引入微服务,就是因为代码复杂后需要更多人力资源进行维护,当人员多了,就需要配套的管理,将人员分为多个组,每个组分工进行处理所以我们需要将服务器的功能拆分由不同的组进行管理也更方便功能的复用。
引入微服务付出的代价?
1.系统的性能会下降:因为我们拆分成更多的服务器,那服务器之间还需要通过网络通信的方式传递数据,而网络通信的速度又很慢。
2.系统复杂程度变高:虽然引入微服务降低了服务器的复杂程度,但是提高了系统的复杂程度,因为服务器更多,出现问题的概率就会变大,这时候我们还需要别的手段来保证不出错。
(三)一些术语的简单理解
1.应用/系统
一个应用,就是一组服务器程序
2.模块/组件
一个应用中会有很多独立的功能,就可以称为一个模块
3.分布式
引入多台主机/服务器一起完成一系列的工作
4.集群
与分布式一样,不过这里的主机不一定真的是一台计算机也可能是不同程序(逻辑上的多个主机)
5.主/从
分布式中的典型结构,服务器可分为主服务器和从服务器,从服务器中的数据要从主服务器中同步
6.中间件
和业务无关的服务比如:数据库,缓存,消息队列
7.可用性
系统整体可用的时间/总时间,就是我们的可用性
8.响应时长
衡量服务器的性能,同一功能下越小就代表服务器的性能越高
9.吞吐和并发
服务器处理请求的能力,也可以衡量服务器的性能
(四)redis的一些特性
1.In-memory data structrue
mysql是在硬盘中通过“表”的方式来存储数据,又叫关系型数据,redis是在内存中通过“键值对”的方式存储数据,又叫非关系型数据,redis中键值对里的key都是String类型,而value可以是Strings,hashes,lists,sets等数据结构
2.Programmability
redis是可编程的,我们针对redis的操作可以直接通过简单的交互式命令来进行操作,也可以通过脚本的方式,批量执行操作,比如我们可以使用Lua
3.Extensibility
redis是可扩展的,redis只给我们提供了一组api,如果我们觉得redis功能不够强大,我们可以通过扩展的方式,来让redis支持更多的数据结构和更多命令(我们可以使用C,C++,Rust来进行扩展)
4.Persistence
redis数据是可以持久化的,redis把数据存储在内存上,那我们如果开关机,我们的数据会被清空,这种情况是不允许的,所以redis也会把数据存储在硬盘上,内存为主,硬盘为辅,硬盘就相当于内存的备份,如果计算机重启内存数据丢失,我们就会加载硬盘中备份的数据
5.Clustering
redis是支持集群的,作为一个分布式系统的组件,既然应用于分布式环境上,就要支持集群,就类似于数据库的“分库分表”,一个redis中存储数据有限,引入多个主机,部署多个redis即可
6.High availability
redis是高可用的,reids也支持主从结构,就像服务器支持主从服务器一样,从结点就相当于主结点的备份
(五)redis为什么这么快?
1.redis数据存储在内存中,比访问硬盘的数据库快很多
2.redis核心功能都比较简单(操作内存的数据结构)
3.redis进行网络通信时使用IO多路复用
4.redis使用单线程模型(更高版本引入了多线程),减少了不必要的线程竞争引发的开销
那之前我们引入多线程不就是因为要提高效率吗?为什么在这里单线程会更快?
其实多线程提高效率是通过我们cpu多核资源来的,所以更适用于cpu密集型任务,但是redis核心任务我们也说了,只是操作内存的数据结构,对cpu的消耗不大,所以也就不必引入多线程
(六)redis能做什么
1.数据库
我们可以将redis作为一个数据库,那什么情况下把redis作为一个数据库呢?大多数情况下,我们首先考虑存储更多的数据而不是效率,但是在一些特定的场景下比如搜索引擎,对于性能的要求就比较高,我们需要把所有检索的数据存储在内存的,就是用类似redis这样的数据库来完成
2.缓存
上述我们说到的二八原则就是把热点数据拿出来放在redis中,redis存的部分数据,而mysql中存储的才是全量数据,redis数据丢失也可以从mysql中加载回来
3.消息队列
基于redis这个中间件,我们可以实现一个生产者消费者模型,优势:1.解耦合,2.削峰填谷
4.session存储
我们知道cookie是用来实现用户身份信息的保存,但是需要session的配合,cookie本质只是在浏览器这边存了一个用户身份标识,真正存用户数据的还是服务器中的session,但是我们可能有很多应用服务器,我们登录一个服务器会给我们一个cookie,但是我们下一次访问时可能负载均衡器会给我们分配到其他的应用服务器上,就需要我们重新登录重新上面的请求
那如何解决上面的问题?
1.想办法让负载均衡器把同一个用户的请求一直分配到同一个服务器
2.把会话数据单独分配一个服务器(redis)