SpringCloud GitHub Demo(看完文章的同学可以自己练手玩玩):
项目结构图:
二、集群/分布式/微服务/SOA是什么?
像我这种技术小白,看到这些词(集群/分布式/微服务/SOA)的时候,感觉就是遥不可及的(高大尚的技术!!)。就好像刚学Java面向对象的时候,在论坛上翻阅资料的时候,无意看到"面向切面编程",也认为这是遥不可及的(高大尚的技术!!)。
但真正接触到"面向切面编程"的时候,发现原来就是如此啊,也没什么大不了的。只不过当时被它的名字给唬住了...
不知道各位在刚接触这些名字集群/分布式/微服务/SOA的时候,有没有被唬住了呢??
下面我就简单说说这些名词的意思
2.1什么是集群
以下内容来源维基百科:
计算机集群简称集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。集群计算机通常用来改进单个计算机的计算速度和/或可靠性。一般情况下集群计算机比单个计算机,比如工作站或超级计算机性能价格比要高得多
集群技术特点:
通过多台计算机完成同一个工作,达到更高的效率。
两机或多机内容、工作过程等完全一样。如果一台死机,另一台可以起作用。
在维基百科上说得也挺明白的了,我来举个例子吧。
小周在公司写Java程序,但公司业务在发展,一个Java开发者可能忙不过来,小周有的时候也得请个假呀。于是请了3y过去一起做Java开发。平时小周和3y就写Java程序,但3y可能有事要回学校一趟。没事,公司还有小周做Java开发呢,公司开发还能继续运作。
3y跟小周都是做Java开发。
3y来了,小周的工作可以分担一些。
3y请假了,还有小周在呢。
我写了一个910便利网发布到服务器去了,现在越来越多的人访问了,访问有点慢,怎么办???很简单,(只有充钱才能变强),加配置吧(加cpu,加内存)。升级完配置之后,访问人数越来越多,于是发现又不禁用啦,在这台机器上加配置已经解决不了了,怎么办???很简单,(只有充钱才能变强),我再买一台服务器,将910便利网也发布到新买的这台服务器上去。
特点:
这两台服务器都是运行同一个系统--->910便利网
好处:
本来只有一台机器处理访问,现在有两台机器处理访问了,分担了压力。
如果其中一台忘记缴费了,暂时用不了了。没关系,还有另一台可以用呢。
集群:同一个业务,部署在多个服务器上(不同的服务器运行同样的代码,干同一件事)
2.2什么是分布式
以下内容来源维基百科:
分布式系统是一组计算机,通过网络相互连接传递消息与通信后并协调它们的行为而形成的系统。 组件之间彼此进行交互以实现一个共同的目标。
我也来举个例子来说明一下吧:
现在公司有小周和3y一起做Java开发,做Java开发一般jQuery,AJAX都能写一点,所以这些活都由我们来干。可是呢,3y对前端不是很熟,有的时候调试半天都调不出来。老板认为3y是真的菜!于是让小周专门来处理前端的事情。这样3y就高兴了,可以专心写自己的Java,前端就专门交由小周负责了。于是,小周和3y就变成了协作开发。
3y对前端不熟(能写出来),但在调试的时候可能会花费很多时间
小周来专门做前端的事,3y可以专心写自己的Java程序了。
都是为了项目正常运行以及迭代。
我的910便利网已经部署到两台服务器去了,但是越来越多的人去访问。现在也逐渐承受不住啦。那现在怎么办啊??那继续充钱变强??作为一个理智的我,肯定得想想是哪里有问题。现在910便利网的模块有好几个,全都丢在同一个Tomcat里边。
其实有些模块的访问是很低的(比如后台管理),那我可不可以这样做:将每个模块抽取独立出来,访问量大的模块用好的服务器装着,没啥人访问的模块用差的服务器装着。这样的好处是:一、资源合理利用了(没人访问的模块用性能差的服务器,访问量大的模块单独提升性能就好了)。二、耦合度降低了:每个模块独立出来,各干各的事(专业的人做专业的事),便于扩展
特点:
将910便利网的功能拆分,模块之间独立,在使用的时候再将这些独立的模块组合起来就是一个系统了。
好处:
模块之间独立,各做各的事,便于扩展,复用性高
高吞吐量。某个任务需要一个机器运行10个小时,将该任务用10台机器的分布式跑(将这个任务拆分成10个小任务),可能2个小时就跑完了
分布式:一个业务分拆多个子业务,部署在不同的服务器上(不同的服务器,运行不同的代码,为了同一个目的)
2.3集群/分布式
集群和分布式并不冲突,可以有分布式集群
现在3y的公司规模变大了,有5个小伙子写Java,4个小伙子写前端,2个小伙子做测试,1个小伙子做DBA。
Java,前端,测试,DBA的关系看作是分布式的
5个Java看作是集群的(前端,测试同理)...
2.4分布式/微服务/SOA
其实我认为分布式/微服务/SOA这三个概念是差不多的,了解了其中的一个,然后将自己的理解往上面套就好了。没必要细分每个的具体概念~~(当然了,我很期待有大佬可以在评论区留言说下自己的看法哈)
参考资料:
分布式与集群的区别是什么?https://www.zhihu.com/question/20004877
分布式、集群、微服务、SOA 之间的区别https://blog.csdn.net/heatdeath/article/details/79038795
三、CAP理论
从上面所讲的分布式概念我们已经知道,分布式简单理解就是:一个业务分拆多个子业务,部署在不同的服务器上
一般来说,一个子业务我们称为节点。
如果你接触过一些分布式的基础概念,那肯定会听过CAP这个理论。就比如说:你学了MySQL的InnoDB存储引擎相关知识,你肯定听过ACID!
首先,我们来看一下CAP分别代表的是什么意思:
C:数据一致性(consistency)
所有节点拥有数据的最新版本
A:可用性(availability)
数据具备高可用性
P:分区容错性(partition-tolerance)
容忍网络出现分区,分区之间网络不可达。
下面有三个节点(它们是集群的),此时三个节点都能够相互通信:
由于我们的系统是分布式的,节点之间的通信是通过网络来进行的。只要是分布式系统,那很有可能会出现一种情况:因为一些故障,使得有些节点之间不连通了,整个网络就分成了几块区域。
数据就散布在了这些不连通的区域中,这就叫分区
现在出现了网络分区后,此时有一个请求过来了,想要注册一个账户。
此时我们节点一和节点三是不可通信的,这就有了抉择:
如果允许当前用户注册一个账户,此时注册的记录数据只会在节点一和节点二或者节点二和节点三同步,因为节点一和节点三的记录不能同步的。
这种情况其实就是选择了可用性(availability),抛弃了数据一致性(consistency)
如果不允许当前用户注册一个账户(就是要等到节点一和节点三恢复通信)。节点一和节点三一旦恢复通信,我们就可以保证节点拥有的数据是最新版本。
这种情况其实就是抛弃了可用性(availability),选择了数据一致性(consistency)
3.1再次梳理一下CAP理论
一般我们说的分布式系统,P:分区容错性(partition-tolerance)这个是必需的,这是客观存在的。
CAP是无法完全兼顾的,从上面的例子也可以看出,我们可以选AP,也可以选CP。但是,要注意的是:不是说选了AP,C就完全抛弃了。不是说选了CP,A就完全抛弃了!
在CAP理论中,C所表示的一致性是强一致性(每个节点的数据都是最新版本),其实一致性还有其他级别的:
弱一致性:弱一致性是相对于强一致性而言,它不保证总能得到最新的值;
最终一致性(eventual consistency):放宽对时间的要求,在被调完成操作响应后的某个时间点,被调多个节点的数据最终达成一致
可用性的值域可以定义成0到100%的连续区间。
所以,CAP理论定义的其实是在容忍网络分区的条件下,“强一致性”和“极致可用性”无法同时达到。
参考资料:
CAP理论中的P到底是个什么意思?https://www.zhihu.com/question/54105974
浅谈分布式系统的基本问题:可用性与一致性:https://m.aliyun.com/yunqi/articles/2709
分布式系统的CAP理论:http://www.hollischuang.com/archives/666
为什么CAP理论在舍弃P的情况下,可以有完美的CA?https://www.zhihu.com/question/285878189
不懂点CAP理论,你好意思说你是做分布式的吗?http://www.yunweipai.com/archives/8432.html
扩展阅读:
浅谈分布式事务:https://m.aliyun.com/yunqi/articles/230242
四、SpringCloud就是这么简单
相信大家读到这里,对分布式/微服务已经有一定的了解了,其实单从概念来说,是非常容易理解的。只是很可能被它的名字给唬住了。
下面我就来讲讲SpringCloud最基础的知识~
4.1为什么需要SpringCloud?
前面也讲了,从分布式/微服务的角度而言:就是把我们一大的项目,分解成多个小的模块。这些小的模块组合起来,完成功能。
举个可能不太恰当的例子(现实可能不会这么拆分,但意思到位就好了):
拆分出多个模块以后,就会出现各种各样的问题,而SpringCloud提供了一整套的解决方案!
注:这些模块是独立成一个子系统的(不同主机)。
SpringCloud的基础功能:
服务治理: Spring Cloud Eureka
客户端负载均衡: Spring Cloud Ribbon
服务容错保护: Spring Cloud Hystrix
声明式服务调用: Spring Cloud Feign
API网关服务:Spring Cloud Zuul
分布式配置中心: Spring Cloud Config
SpringCloud的高级功能(本文不讲):
消息总线: Spring Cloud Bus
消息驱动的微服务: Spring Cloud Stream
分布式服务跟踪: Spring Cloud Sleuth
五、引出Eureka
那会出现什么问题呢??首当其冲的就是子系统之间的通讯问题。子系统与子系统之间不是在同一个环境下,那就需要远程调用。远程调用可能就会想到httpClient,WebService等等这些技术来实现。
既然是远程调用,就必须知道ip地址,我们可能有以下的场景。
功能实现一:A服务需要调用B服务
在A服务的代码里面调用B服务,显式通过IP地址调用:http://123.123.123.123:8888/java3y/3
功能实现二:A服务调用B服务,B服务调用C服务,C服务调用D服务
在A服务的代码里面调用B服务,显式通过IP地址调用:http://123.123.123.123:8888/java3y/3,(同样地)B->C,C->D
功能实现三:D服务调用B服务,B服务调用C服务
在D服务的代码里面调用B服务,显式通过IP地址调用:http://123.123.123.123:8888/java3y/3,(同样地)B->C
.....等等等等
万一,我们B服务的IP地址变了,想想会出现什么问题:A服务,D服务(等等)需要手动更新B服务的地址
在服务多的情况下,手动来维护这些静态配置就是噩梦!
为了解决微服务架构中的 服务实例维护问题(ip地址), 产生了大量的 服务治理框架和产品。 这些框架和产品的实现都围绕着服务注册与服务发现机制来完成对微服务应用实例的 自动化管理。
在SpringCloud中我们的服务治理框架一般使用的就是Eureka。
我们的问题:
现在有A、B、C、D四个服务,它们之间会互相调用(而且IP地址很可能会发生变化),一旦某个服务的IP地址变了,那服务中的代码要跟着变,手动维护这些静态配置(IP)非常麻烦!
Eureka是这样解决上面所说的情况的:
创建一个E服务,将A、B、C、D四个服务的信息都注册到E服务上,E服务维护这些已经注册进来的信息
A、B、C、D四个服务都可以拿到Eureka(服务E)那份注册清单。A、B、C、D四个服务互相调用不再通过具体的IP地址,而是通过服务名来调用!
拿到注册清单--->注册清单上有服务名--->自然就能够拿到服务具体的位置了(IP)。
其实简单来说就是:代码中通过服务名找到对应的IP地址(IP地址会变,但服务名一般不会变)
5.1Eureka细节
Eureka专门用于给其他服务注册的称为Eureka Server(服务注册中心),其余注册到Eureka Server的服务称为Eureka Client。
在Eureka Server一般我们会这样配置:
register-with-eureka: false #false表示不向注册中心注册自己。 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
Eureka Client分为服务提供者和服务消费者。
但很可能,某服务既是服务提供者又是服务消费者。
如果在网上看到SpringCloud的某个服务配置没有"注册"到Eureka-Server也不用过于惊讶(但是它是可以获取Eureka服务清单的)
很可能只是作者把该服务认作为单纯的服务消费者,单纯的服务消费者无需对外提供服务,也就无须注册到Eureka中了
eureka: client: register-with-eureka: false # 当前微服务不注册到eureka中(消费端) service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
下面是Eureka的治理机制:
服务提供者
服务注册:启动的时候会通过发送REST请求的方式将自己注册到Eureka Server上,同时带上了自身服务的一些元数据信息。
**服务续约:**在注册完服务之后,服务提供者会维护一个心跳用来持续告诉Eureka Server: "我还活着 ” 、
服务下线:当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给Eureka Server, 告诉服务注册中心:“我要下线了 ”。
服务消费者
获取服务:当我们启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单
服务调用:服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。在进行服务调用的时候,优先访问同处一个Zone中的服务提供方。
Eureka Server(服务注册中心):
失效剔除:默认每隔一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔除出去。
自我保护:。EurekaServer 在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%(通常由于网络不稳定导致)。 Eureka Server会将当前的实例注册信息保护起来, 让这些实例不会过期,尽可能保护这些注册信息。
最后,我们就有了这张图:
举个例子:
3y跟女朋友去东站的东方宝泰逛街,但不知道东方宝泰有什么好玩的。于是就去物业搜了一下东方宝泰商户清单,发现一楼有优衣库,二楼有星巴克,三楼有麦当劳。
在优衣库旁边,有新开张的KFC,在墙壁打上了很大的标识“欢迎KFC入驻东方宝泰”。
商家们需要定时交物业费给物业。
物业维持东方宝泰的稳定性。如果某个商家不想在东方宝泰运营了,告诉了物业。物业自然就会将其在东方宝泰商户清单去除。
优秀博文:
Spring Cloud Eureka详解:https://blog.csdn.net/sunhuiliang85/article/details/76222517
《Spring Cloud Netflix》 -- 服务注册和服务发现-Eureka 的使用:https://zhuanlan.zhihu.com/p/26472547
微服务架构:Eureka参数配置项详解:https://www.cnblogs.com/fangfuhai/p/7070325.html