Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的各种组件。

注:Spring Boot 简单理解就是简化 Spring 项目的搭建、配置、组合的框架。因为与构建微服务本身没有直接关系,所以本文不对 Spring Boot 进行展开。另外本文有一些例子涉及到 Spring 和 Spring Boot,建议先了解一下 Spring 和 Spring Boot 再阅读本文。

本文的阅读对象主要是没有接触过服务架构,想对其有一个宏观的了解的同学。

本文将从 Spring Cloud 出发,分两小节讲述微服务框架的「五脏六腑」:

  • 第一小节「服务架构」旨在说明的包括两点,一服务架构是什么及其必要性;二是服务架构的基本组成。为什么第一节写服务架构而不是微服务架构呢?原因主要是微服务架构本身与服务架构有着千丝万缕的关系,服务架构是微服务架构的根基。

  • 第二小节「五脏六腑」则将结合 Spring Cloud 这个特例来介绍一个完整的微服务框架的组成。

服务架构

为了方便理解,我先讲一个小故事:(改编自一知乎答主)

Martin(微服务提出者也叫 Martin)刚来到公司时是一个基层员工,它上面有经理、老板,那个时候所有人都听老板的指挥。

但是过了两年,公司的人越来越多,原来的模式下整个公司的运作效率太低,管理也很混乱。

于是已经踏上中层岗位的 Martin 建议老板进行部门划分(服务化),专门的部门只做专门的事情(单一职责)。例如研发部门只做研发,人事部门只做招聘。

老板听取了 Martin 的意见,对公司的组织架构进行了调整。

有一天,Martin 发现公司的部门越来越多,各个部门并不能完全知道对方所做的事情,这对跨部门协作(服务调用)带来了困难。

行政部门会(注册中心)来记录所有的部门,每当有新的部门行政都会记录下来(服务注册),然后公布出来让所有部门知道(服务发现)。

在新的组织架构下,公司的效率逐步提高。老板也给 Martin 发了大量奖金作为奖励,Martin 从此赢取白富美走向了人生巅峰。

这是一个公司组织架构演变的故事,主要讲的是随着公司规模的扩大,组织从集中化管理到分布化管理的过程。

映射到我们的信息系统里来也是一样的,随着我们的系统越来越复杂,变得难以管理,也有人想到去拆分然后治理。在解决复杂问题上,分治可以说是一个屡试不爽的办法。

服务化即是拆解的一种手段。而上面圆括号里面的内容其实就对应了一个服务化架构的最小组成元素,分别是服务、服务调用、注册中心、服务注册、服务发现。有了这些基本的组成要素,就可以实现一个最简单的服务架构。

面向服务的架构和微服务架构

面向服务的架构(SOA)和微服务架构是目前两种主流的服务化架构,都符合上面的例子,也有上面提到的所有组件。这两种服务架构有很多可以讲的,但是与本文的相关性不大,本文不做会过多展开,只简单介绍一下两者的区别。

准确地说微服务是去 ESB(企业服务总线)的 SOA。ESB 借鉴了计算机组成原理中的通信模型 —— 总线,所有需要和外部系统通信的系统,通过 ESB 进行标准化地转换从而消除协议、异构系统之间的差异,这样就可以利用现有的系统构建一个全新的松耦合的异构的分布式系统。微服务架构去掉 ESB,本质上是一种去中心化的思想。

五脏六腑

心脏

顺着上一节的思路,从最简单、最核心的问题出发,假设服务 A 要调用服务 B,会有什么问题?

  • 服务在哪?(服务治理问题)

  • 怎么调用?(服务调用问题)

这两个是最核心的问题,也是任何微服务框架首要解决的两个问题。

为了解决第一个问题 Spring Cloud 提供了 Eureka、Zookeeper、Cloud Foundry、Consul 等服务治理框架的集成。它们的工作模式是将所有的微服务注册到一个 Server 上,然后通过心跳进行服务健康监测。这样服务 A 调用 B 时可以从注册中心拿到可用的服务 B 的地址、端口进行调用。

第二个服务调用有人可能认为就是一个简单的 HTTP 或者 RPC 调用,不是什么问题。但是在分布式的场景下,服务调用需要考虑的因素会更多。比如一个服务有多个实例,此时请求进来了交给谁处理,请求的负载怎么平衡到各个实例,都是比较棘手的问题。Spring Cloud 提供了两种服务调用的方式:一种是 Ribbon + restTemplate,另一种是 Feign。

其中 Ribbon 是基于 HTTP 和 TCP 客户端的负载均衡器,restTemplate 是 Spring 提供的 Restful 远程调用的模板,两者结合就可以达到远程调用的负载均衡。

而 Feign 是一个更加声明式的 HTTP 客户端,开发者可以像调用本地方法一样调用它,完全感觉不到是远程调用,结合 Ribbon 也可以做负载均衡。

既然两个问题都得到了解决,我们就用一个例子来进一步说明一下,例子包含了微服务中最基本的三个角色(注册中心、服务提供者、服务消费者):

注册中心

注解 @EnableEurekaServer 表示该 Spring Boot 应用是一个注册中心。

@EnableEurekaServer@SpringBootApplicationpublic class EurekaserverApplication {   public static void main(String[] args) {       SpringApplication.run(EurekaserverApplication.class, args);   }}@SpringBootApplicationpublic class EurekaserverApplication {   public static void main(String[] args) {       SpringApplication.run(EurekaserverApplication.class, args);   }}

eureka.client.registerWithEureka: false 和fetchRegistry: false 来表明自己是一个 eureka server。

server: port: 8080eureka: instance:   hostname: localhost client:   registerWithEureka: false   fetchRegistry: false   serviceUrl:     defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ port: 8080

eureka: instance:   hostname: localhost client:   registerWithEureka: false   fetchRegistry: false   serviceUrl:     defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

service-hello 服务

注解 @EnableEurekaClient 表示他是一个 Eureka 客户端,它会在注册中心注册自己。

注解 @RestController 表示这是一个控制器,@RequestMapping("/hello") 表示匹配到请求 '/hello' 时会调用该方法进行响应。

@SpringBootApplication@EnableEurekaClient@RestControllerpublic class ServiceHelloApplication {   public static void main(String[] args) {       SpringApplication.run(ServiceHelloApplication.class, args);   }   @Value("${server.port}")   String port;   @RequestMapping("/hello")   public String home(@RequestParam String name) {       return "hello "+name+",i am from port:" +port;   }}@EnableEurekaClient@RestControllerpublic class ServiceHelloApplication {

   public static void main(String[] args) {       SpringApplication.run(ServiceHelloApplication.class, args);   }

   @Value("${server.port}")   String port;   @RequestMapping("/hello")   public String home(@RequestParam String name) {       return "hello "+name+",i am from port:" +port;   }

}

注册中心的地址为 http://localhost:8080/eureka/,也就是上面我们定义的。服务名为 service-hello,将会被调用者使用。

eureka: client:   serviceUrl:     defaultZone: http://localhost:8080/eureka/server: port: 8081spring: application:   name: service-hello client:   serviceUrl:     defaultZone: http://localhost:8080/eureka/server: port: 8081spring: application:   name: service-hello

服务消费者 service-ribbon

假设 service-ribbon 端口为 8082,当我们访问 http://localhost:8080/hello 时,HelloControler 接收到请求,并调用 HelloService 中的 helloService 方法,HelloService 中通过定义的 restTemplate 去调用 http://service-hello/hello。此处要注意的是 @LoadBalanced 注解,它表示启用负载均衡。

@SpringBootApplication@EnableDiscoveryClientpublic class ServiceRibbonApplication {   public static void main(String[] args) {       SpringApplication.run(ServiceRibbonApplication.class, args);   }      @Bean   @LoadBalanced   RestTemplate restTemplate() {       return new RestTemplate();   }}@Servicepublic class HelloService {   @Autowired   RestTemplate restTemplate;   public String helloService(String name) {       return restTemplate.getForObject("http://service-hello/hello?name="+name,String.class);   }}@RestControllerpublic class HelloControler {   @Autowired   HelloService helloService;      @RequestMapping(value = "/hello")   public String hello(@RequestParam String name){       return helloService.helloService(name);   }}@EnableDiscoveryClientpublic class ServiceRibbonApplication {

   public static void main(String[] args) {       SpringApplication.run(ServiceRibbonApplication.class, args);   }

   @Bean   @LoadBalanced   RestTemplate restTemplate() {       return new RestTemplate();   }

}

@Servicepublic class HelloService {

   @Autowired   RestTemplate restTemplate;

   public String helloService(String name) {       return restTemplate.getForObject("http://service-hello/hello?name="+name,String.class);   }

}

@RestControllerpublic class HelloControler {

   @Autowired   HelloService helloService;

   @RequestMapping(value = "/hello")   public String hello(@RequestParam String name){       return helloService.helloService(name);   }

}

至此其实一个微服务应用的雏形已经搭建出来了,服务治理、服务调用可以说是「五脏六腑」中的「心脏」。

心脏的依托

接下来我们要进一步思考的是「五脏六腑」中其余的部分,因为少了它们人也是活不久的。下面通过一个问题或需求对应一个组件的方式进行介绍。

服务“雪崩”与断路器

由于网络等原因,服务并不能保证 100% 可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗殆尽,导致服务瘫痪。

由于服务与服务之间存在依赖,故障会在调用链路上传播,导致整个微服务系统崩溃,这就是服务故障的“雪崩”效应。

为了解决这个问题,Spring Cloud 提供了对 Hystrix 断路器的集成,当服务调用失败的频次达到一定阈值,断路器将被开启,降级的策略可以开发者制定,一般是返回一个固定值。这样就能够避免连锁故障。

此外 Spring Cloud 还提供 Hystrix Dashboard 和 Hystrix Turbine,帮助我们进行监控和聚合监控。

服务暴露与路由网关

微服务中的服务很多,直接暴露给用户一是不安全,二是对用户不友好。因此在微服务和面向服务的架构中,通常会有一个路由网关的角色,来负责路由转发和过滤。对应到 Spring Cloud 中有 Zuul 和 Gateway 两个组件可用。

路由网关接收了所有的用户请求,有着很高的负载,因此它通常是一个集群。用户的请求会先经过一层负载均衡被发到路由网关。

服务配置与配置中心

在微服务应用中,服务数量巨多,而每个服务不同环境都有着不同的配置,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。需要注意的是此处的配置与注册中心注册的配置信息是两个概念,此处的配置是服务本身的一些配置信息,如下图:

Spring Cloud 提供了 Spring Cloud Config 组件,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程 Git 仓库中,帮助我们管理服务的配置信息。

信息同步与消息总线

前一个问题讲到了每个服务都有一些配置信息,那么配置信息更新了我们该怎么办,手动一个个去更新?当然不是,Spring Cloud 提供了 Spring Cloud Bus 组件,它通过轻量消息代理连接各个分布的节点。当配置信息更新的时候,我们只要更新一个节点的配置,这个更新就会被广播到这个分布式系统中。

问题定位与链路追踪

在微服务系统中,服务之间可以相互调用,因此我们一个请求可能会一条调用链,而整个系统会存在一张调用网,其中任意一个服务调用失败或网络超时都可能导致整个请求失败。因为调用关系的复杂,这给问题的定位造成了极大的困难,这也是必须提供服务链路追踪的原因。

Spring Cloud 为我们提供了 Spring Cloud Sleuth 组件,它能够跟进一个请求到底有哪些服务参与,参与的顺序是怎样的,从而达到每个请求的步骤清晰可见。借助服务链路追踪,我们可以快速定位问题。

至此,Spring Cloud 的所有基础组件都介绍完了。但是目前所有的组件介绍都是分散的,它们组合起来,完整的样子是什么样的?如下图:

偷懒偷了张图,图中漏掉了 Config Server 和链路追踪组件。但是结合上文的介绍,我们大致可以脑补出这两个东西在图中的位置。Config Server 是一个与所有服务相连的服务集群,链路追踪组件则集成在每个服务中。

小结

服务治理为心脏,路由网关、消息中心、断路器、链路追踪、配置中心等为依托,构造了整个微服务框架的「五脏六腑」。当然,一个微服务系统远比本文所写的复杂得多,尤其是在不同的业务场景之下,因此想要更深入地了解它就需要我们不断地去实践。而作为前端,我了解这些内容一是为了更好地了解整个请求的流程,二是为了后续在 SOA 中接入 Node 子服务积累相关知识。

最后分享一句有趣的调侃 Spring 的话:在 Spring 中没有什么是一个注解解决不了的,如果有,那么就用两个注解。

作者:曹林华

来源:blog.51cto.com/13527416/2085258

秒杀架构设计

前言

最近在部门内部分享了原来在电商业务做秒杀活动的整体思路,大家对这次分享反馈还不错,所以我就简单整理了一下,分享给大家参考参考。

业务介绍

什么是秒杀?通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动

比如说京东秒杀,就是一种定时定量秒杀,在规定的时间内,无论商品是否秒杀完毕,该场次的秒杀活动都会结束。这种秒杀,对时间不是特别严格,只要下手快点,秒中的概率还是比较大的。

淘宝以前就做过一元抢购,一般都是限量 1 件商品,同时价格低到「令人发齿」,这种秒杀一般都在开始时间 1 到 3 秒内就已经抢光了,参与这个秒杀一般都是看运气的,不必太强求。

业务特点

瞬时并发量大

秒杀时会有大量用户在同一时间进行抢购,瞬时并发访问量突增 10 倍,甚至 100 倍以上都有。

库存量少

一般秒杀活动商品量很少,这就导致了只有极少量用户能成功购买到。

业务简单

流程比较简单,一般都是下订单、扣库存、支付订单。

技术难点

现有业务的冲击

秒杀是营销活动中的一种,如果和其他营销活动应用部署在同一服务器上,肯定会对现有其他活动造成冲击,极端情况下可能导致整个电商系统服务宕机。

直接下订单

下单页面是一个正常的 URL 地址,需要控制在秒杀开始前,不能下订单,只能浏览对应活动商品的信息。简单来说,需要 Disable 订单按钮。

页面流量突增

秒杀活动开始前后,会有很多用户请求对应商品页面,会造成后台服务器的流量突增,同时对应的网络带宽增加,需要控制商品页面的流量不会对后台服务器、DB、Redis 等组件的造成过大的压力

架构设计思想

限流

由于活动库存量一般都是很少,对应的只有少部分用户才能秒杀成功。所以我们需要限制大部分用户流量,只准少量用户流量进入后端服务器。

削峰

秒杀开始的那一瞬间,会有大量用户冲击进来,所以在开始时候会有一个瞬间流量峰值。如何把瞬间的流量峰值变得更平缓,是能否成功设计好秒杀系统的关键因素。实现流量削峰填谷,一般的采用缓存和 MQ 中间件来解决。

异步

秒杀其实可以当做高并发系统来处理,在这个时候,可以考虑从业务上做兼容,将同步的业务,设计成异步处理的任务,提高网站的整体可用性。

缓存

秒杀系统的瓶颈主要体现在下订单、扣减库存流程中。在这些流程中主要用到 OLTP 的数据库,类似 MySQL、SQLServer、Oracle。由于数据库底层采用 B+ 树的储存结构,对应我们随机写入与读取的效率,相对较低。如果我们把部分业务逻辑迁移到内存的缓存或者 Redis 中,会极大的提高并发效率。

整体架构

客户端优化

客户端优化主要有两个问题:

秒杀页面

秒杀活动开始前,其实就有很多用户访问该页面了。如果这个页面的一些资源,比如 CSS、JS、图片、商品详情等,都访问后端服务器,甚至 DB 的话,服务肯定会出现不可用的情况。所以一般我们会把这个页面整体进行静态化,并将页面静态化之后的页面分发到 CDN 边缘节点上,起到压力分散的作用。

防止提前下单

防止提前下单主要是在静态化页面中加入一个 JS 文件引用,该 JS 文件包含活动是否开始的标记以及开始时的动态下单页面的 URL 参数。同时,这个 JS 文件是不会被 CDN 系统缓存的,会一直请求后端服务的,所以这个 JS 文件一定要很小。当活动快开始的时候(比如提前),通过后台接口修改这个 JS 文件使之生效。

API 接入层优化

客户端优化,对于不是搞计算机方面的用户还是可以防止住的。但是稍有一定网络基础的用户就起不到作用了,因此服务端也需要加些对应控制,不能信任客户端的任何操作。一般控制分为 2 大类:

限制用户维度访问频率

针对同一个用户( Userid 维度),做页面级别缓存,单元时间内的请求,统一走缓存,返回同一个页面。

限制商品维度访问频率

大量请求同时间段查询同一个商品时,可以做页面级别缓存,不管下回是谁来访问,只要是这个页面就直接返回。

SOA 服务层优化

上面两层只能限制异常用户访问,如果秒杀活动运营的比较好,很多用户都参加了,就会造成系统压力过大甚至宕机,因此需要后端流量控制。

对于后端系统的控制可以通过消息队列、异步处理、提高并发等方式解决。对于超过系统水位线的请求,直接采取 「Fail-Fast」原则,拒绝掉。

秒杀整体流程图

秒杀系统核心在于层层过滤,逐渐递减瞬时访问压力,减少最终对数据库的冲击。通过上面流程图就会发现压力最大的地方在哪里?

MQ 排队服务,只要 MQ 排队服务顶住,后面下订单与扣减库存的压力都是自己能控制的,根据数据库的压力,可以定制化创建订单消费者的数量,避免出现消费者数据量过多,导致数据库压力过大或者直接宕机。

库存服务专门为秒杀的商品提供库存管理,实现提前锁定库存,避免超卖的现象。同时,通过超时处理任务发现已抢到商品,但未付款的订单,并在规定付款时间后,处理这些订单,将恢复订单商品对应的库存量。

总结

核心思想:层层过滤

  • 尽量将请求拦截在上游,降低下游的压力

  • 充分利用缓存与消息队列,提高请求处理速度以及削峰填谷的作用

精彩回顾

♡ 程序员究竟能干多少年?

♡ 互联网公司各岗位真实工作内容起底

♡ 一次尴尬的采访和程序员的传奇脑洞!

♡ 天一冷,程序员都穿上格子衫

♡ 史上最真实的行业鄙视链曝光

♡ IT公司老板落水,各部门员工怎么救

♡ 宿命之战:程序员VS产品经理

♡ 作为一个前端,可以如何机智地弄坏一台电脑?

♡ 程序员跟产品经理打起来了,这是一个需求引发的血案...

♡ 后端说,你个前端不会用 headers吧,我怒了!

♡ 有个厉害的程序员女朋友是什么体验?

♡ 多年来,程序员经常加班的真相终于揭开了…

从 Spring Cloud 看一个微服务框架的五脏六腑相关推荐

  1. 从 Spring Cloud 看一个微服务框架的「五脏六腑」

    点击上方"Java学习之道",选择"关注"公众号 每天早晨,干货准时奉上! 本文作者:酷家乐前端团队 来自:webfe.kujiale.com/spring-c ...

  2. 从 Spring Cloud 看一个微服务框架的「五脏六腑]

    https://webfe.kujiale.com/spring-could-heart/ Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的 ...

  3. 微服务等于 Spring Cloud?了解微服务架构和框架

    点击上方"芋道源码",选择"设为星标" 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 8:55 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | J ...

  4. 【福利】赠书:Spring Cloud与Docker微服务架构实战(第2版)

    本次福利送出好友周立的第二版书籍! 正在关注和使用Spring Cloud的朋友们不要错过哦! 内容提要 <Spring Cloud与Docker微服务架构实战(第2版)>基于Spring ...

  5. 《深入理解 Spring Cloud 与微服务构建》第十七章 使用 Spring Cloud OAuth2 保护微服务系统

    <深入理解 Spring Cloud 与微服务构建>第十七章 使用 Spring Cloud OAuth2 保护微服务系统 文章目录 <深入理解 Spring Cloud 与微服务构 ...

  6. Spring Cloud(5)---基于 Spring Cloud 完整的微服务架构实战

    基于 Spring Cloud 完整的微服务架构实战 技术栈 Spring boot - 微服务的入门级微框架,用来简化 Spring 应用的初始搭建以及开发过程. Eureka - 云端服务发现,一 ...

  7. Spring Cloud OAuth2 JWT 微服务认证服务器得构建

    文章目录 Spring Cloud OAuth2 JWT 微服务认证服务器得构建 前言 认证服务得搭建 `AuthorizationServer` `WebSecurityConfig` `Autho ...

  8. Spring Cloud Alibaba 大型微服务项目实战

    作者介绍 程序员十三,多年一线开发经验,历任高级开发工程师.后端主程.技术部门主管等职位.同时也是开源项目的爱好者和贡献者.掘金优秀作者.CSDN 博客专家.实体图书作者.专栏作者.视频讲师. 小册介 ...

  9. Spring Cloud Hoxton 版本微服务项目搭建 admin 监控客户端

    Spring Cloud Hoxton 版本微服务项目搭建 admin 监控客户端 前言 在上一篇文章博主已经讲解了admin 管理中心服务项目如何创建,不会的话可以前往学习,传送门:Spring C ...

最新文章

  1. asp用于取代什么技术_苹果Mini LED晶粒四季度量产,用于新iPad Pro,三安光电或成赢家...
  2. 使用case语句的3个诀窍
  3. Spring IOC基础概念总结:何为控制?何为反转?控制了什么?反转了哪里?
  4. 南抖音北快手,智障界的两泰斗
  5. TransE算法的整理
  6. 音视频处理入门基础知识
  7. qt 实现、区分鼠标单击,双击事件
  8. windows环境下:安装MySQL8.0;同时安装MySQL5.7
  9. xcopy 跳过已经存在的_南京的野猪已经会逛奶茶店了?!
  10. 八、python爬虫伪装 [免费伪装ip伪装请求头]
  11. 基于卷积自编码网络结构的图像修复
  12. 计算机网络daytime实现之java/python/c++版本
  13. LoraWan协议剖析,快速掌握协议要点
  14. Trinity使用流程
  15. 2.本地配置yum源
  16. 《淮南师范学院学报》(双月刊)投稿须知
  17. Python实现炸金花游戏的示例代码
  18. FreeChinaNet登陆器
  19. python 中的np.zeros()和np.ones()函数
  20. 【C语言程序设计】C语言生兔子问题!

热门文章

  1. 百度校园招聘历年经典面试题汇总:Java开发岗
  2. ESFJ型人格的性格缺陷和心理问题分析
  3. 【图像处理】——Python+opencv实现图像的hu不变矩特征提取(含原理、推导过程、应用、代码等)
  4. Jobs乔布斯传总结
  5. 图像边缘检测经典算子及MATLAB实现
  6. Java中的相除()和取余(%)
  7. ONNX 模型的静态量化和动态量化
  8. 小如雪花的微尘计算机阅读答案,《有趣的“三”》阅读答案
  9. 成功不难,改变习惯而已!
  10. 【健康生活,从BMI开始——Melendez的Android版本BMI计算器开源了】