随着业务的发展,无数公司开始面向服务开发,转向微服务架构。java
说句大实话,今年秋招,算法和Java
岗人才爆炸,不容易。nginx
忙着找工做,很久没写过博客了。华软新版本基本完成,趁着有时间正好给你们讲一讲传说中的微服务架构。算法
这里的微服务,并非单指咱们用的spring-cloud
,spring-cloud
只是微服务的一种最佳实践。对于创业来讲,在没有稳定的资金支撑自研中间件的状况下,spring-cloud
是咱们最好的选择。spring
在提出微服务架构以前,咱们先分析一下咱们以往的系统有哪些问题。segmentfault
单体架构,就像咱们以前写得系统同样,一个spring-boot
项目实现了全部的业务逻辑,部署的时候mvn package
,java -jar
就算跑起来了一个后台项目。后端
缺点很明显,咱们也遇到过。这里我列出个人几个观点:缓存
若是这个实例宕机了,由于单体应用的强依赖性,整个系统都变为不可用的状态。服务器
由于系统对API
的强依赖,一旦API
实例宕机了,整个系统就完了。网络
对于计量和学校的业务,要求尚未这么高,可是若是对于银行的项目,就没这么容易接受了。架构
除了加服务器,咱们没有办法有针对性地解决高并发。
假设,Alice
的学生管理项目遇到了高并发致使的性能问题,咱们只能这么干。
部署多个API
节点,经过配置nginx
分发策略进行负载均衡。
可是,可能有100
接口,每每只有5-10
个接口是学生/老师们经常使用的,像综合查询之类的不存在并发问题。这样部署属实浪费资源。
咱们没法针对项目中某些经常使用的接口在硬件部署级别上实施优化。
这个是我在参考甲方提供的华软另外一版本的Web
项目得出的思考。
项目架构以下所示:
一个先后端不分离的JavaEE
项目,去调用另外一个专门提供华软接口的.NET
项目。
这是否是看起来很酷,一个项目的后台,采用两种语言,两个服务之间经过HTTP
调用进行通讯。
若是服务之间是经过@Autowired
在容器中进行依赖,那全部功能都须要使用Java
实现,没法发挥各类语言的优点。
假设咱们要保证验证码微服务的高可用,咱们可使用服务注册与发现:
服务注册中心,存储服务到实例地址的映射。
当系统启动时,右侧的三个验证码微服务会向服务注册中心进行注册,表示本身要提供服务。这个过程称为服务注册。
服务注册中心就存储着相似这样的数据:
VerificationCode: - code1.instrument.yunzhiclub.com - code2.instrument.yunzhiclub.com - code3.instrument.yunzhiclub.com
表示验证码有三个微服务提供,地址分别是code1.instrument.yunzhiclub.com
、code2.instrument.yunzhiclub.com
、code3.instrument.yunzhiclub.com
。
若是前台要使用验证码服务,Gateway
会向服务注册中心询问,有哪一个微服务提供验证码的功能,获取到列表,再进行转发。
这个向服务注册中心获取其余服务实例的过程,称为服务发现。
同理,其余微服务想调用该服务,执行的也是与网关相同的服务发现。
为何能保证高可用?
你们思考一下,为何这样设计就能保证高可用呢?
微服务和服务注册中心之间是经过心跳来续约的,若是超过阀值,服务没有向注册中心发送数据,中心就认为这个实例已经死亡,将其从可用列表中剔除。
假设某天,验证码微服务1宕机了,再也不发送本身的心跳信息,服务注册中心中的维护的数据就变成了(实例1被剔除):
VerificationCode: - code2.instrument.yunzhiclub.com - code3.instrument.yunzhiclub.com
这样能保证若是有实例宕机,可让系统以最快的速度恢复。
哪怕用户目前正在请求code1
实例,本次失败了,在一段时间的心跳事后,数据更新,用户重试,也能保证服务可用。
既然这么依赖服务注册中心,那服务注册中心宕机了怎么办?
在系统部署时,服务注册中心每每是三台实例以上的集群。因此大可没必要考虑这个问题。
服务注册中心之间会进行数据同步,我以为这个和路由器之间交换路由表很相似。
上面的诸多技术都是理论,落实到的是spring-cloud
中的一个个组件。
网关:spring-cloud-netflix-zuul
、spring-cloud-gateway
。这里推荐使用spring-cloud-gateway
。
zuul
采用阻塞API
实现,spring
官方认为其存在性能问题,遂放弃维护zuul
,启用新项目spring-cloud-gateway
,采用非阻塞API
实现。
https://stackoverflow.com/questions/47092048/how-is-spring-cloud-gateway-different-from-zuul
服务注册中心:spring-cloud-netflix-eureka
。
又是netflix
家的,我看慕课网的实战课用的基本上都是eureka
。
可是我看新闻好像是因为netflix
公司的闭源,eureka
项目中止维护,替代方案:spring-cloud-consul
。
知识都学会了,换个组件还不是垂手可得?
微服务带来便利的同时,也为咱们带来了服务雪崩问题。
本图片摘抄自博客,感谢原做者的分享:http://www.javashuo.com/article/p-augpkylg-kt.html
就像这个图同样,由于服务之间相互依赖,若是A
服务宕机了,那依赖它的B
服务也不可用,同理,依赖B
的C
、D
服务都不可用。
一个服务的崩溃,致使了整个系统的瘫痪,这就是服务雪崩。
咱们发现雪崩的缘由是虽然B
可用,可是由于A
的瘫痪,致使了B
不可用。因此问题出在服务调用上,咱们须要在服务调用时进行错误处理。
咱们可使用这种策略:当检测到A
崩溃时,B
就不去请求A
(反正请求也是失败),使用本地的降级策略。这个过程称为熔断降级。
降级能够理解为一种兜底策略,差强人意的意思。
好比查询用户数据,用户服务又去调用朋友圈服务的接口。假设朋友圈的接口宕机了,没法获取最新的数据,咱们可使用缓存策略返回上一次缓存的数据。
保证了后台出错,可是给用户的体验也不会不好。
熔断器组件:spring-cloud-hystrix
。
这个是从我刚开始学微服务就一直带着的一个问题。这么多服务,不可能每个都搭一个spring-security
吧?
直到上次计量项目中学习了潘老师对用户认证的实现,才解决这个问题。
全部用户认证放在网关,网关对前台的COOKIE / X-AUTH-TOKEN
进行用户信息的认证,查询出用户后,根据用户信息签发一个JWT Token
。
微服务之间的认证,使用网关签发的JWT Token
。
在《从新定义Spring Cloud实战》一书中,也是推荐网关结合jwt
的认证方式。
微服务架构还须要考虑的一个就是微服务之间的通讯成本。
@Autowired private CourseService courseService;
/** * fallback 兜底策略 */ @FeignClient(value = "course", fallback = CourseClientHystrix.class) public interface CourseClient { @GetMapping(value = "{id}") CourseInfo getCourseInfo(@PathVariable Long id); }
看看代码就是成本的区别,过去就是@Autowired
直接调,如今得用feign
经过网络调,网络通讯确定比本地慢。
因此服务拆分要合理,若是一个服务要求高可用,而且能够接受通讯成本的话,就能够单独拆分微服务。
服务拆分对架构师要求极高,从实现到性能,须要考虑周全。我这种小菜鸡只能写写博客吹吹牛了,如今我还不敢服务拆分呢(就怕拆的很差,把性能拆坏了)。
吹了一篇理论,让你们先了解了解微服务架构,到了本身学的时候也少走些弯路。
看着挺简单的,真正搭spring-cloud
的时候没有看上去那么简单。照着慕课网搭过一个小的,花了好几天时间。
书到用时方恨少,事非通过不知难。