面试遇到的,总结一下,欢迎指正:单体架构跟微服务架构的选择以及优缺点

Posted 凡尘清心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试遇到的,总结一下,欢迎指正:单体架构跟微服务架构的选择以及优缺点相关的知识,希望对你有一定的参考价值。

单体架构:一个war包或者jar包包含了应用的所有功能,称之为单体应用,单体架构中,所有功能集中在一个包中,功能集中、代码跟数据中心化,这是一种比较传统的架构风格,常见的ERP、CRM等系统都以单体架构的方式运行

  优点:

    1.架构简单:使用软件设计中的三层模型,即表示层,业务层,数据访问层

    2.技术单一:项目中不需要很复杂的技术栈

    3.部署成本低:可以部署在一台服务器上

    4.用人成本低:单个程序员可以完成业务接口到数据的整个流程

  缺点:

    1.可用性差:任何一个模块宕机会导致整个系统的宕机

    2.推展能力受限,无法按需伸缩:单体应用只能作为一个整体进行拓展,无法结合业务模块的特点进行伸缩

    3.阻碍技术创新:单体应用往往使用脱衣的技术平台或方案解决所有问题,团队成员必须使用相同的开发语言和架构,想要引入新的框架或技术平台非常困难

    4.部署速度逐渐变慢:随着代码的增加,构建和部署的时间也会增加,在单体应用中,每次功能的变更或缺陷的修复都会导致我们需要重新部署整个应用,全量部署的方式耗时长,影响范围大,风险高

    5.团队协作难度高,多人使用同一个功能,多人进行修改

微服务架构:微服务架构强调一个重点是“业务需要彻底地组件化和服务化”,原有的单个业务会拆分为多个可以独立开发、设计、运行的小应用,这些小应用之间通过服务完成交互和集成,适用与互联网时代,产品迭代周期更短

   优点:

    1.服务拆分粒度更细,遵循单一原则,有利于提高开发效率

    2.可采用http协议进行服务间的调用

    3.可以针对不同服务指定对应的优化方案

    4.微服务之间是松耦合的,灵活性更高

    5.多个团队之间独立开发,加快进入市场需求

    6.微服务是持续交付的巨大推动力,允许在频繁发布不同服务的同时保持系统其他服务的可用性和稳定性

  缺点:

    1.服务粒度小,增加运维开销和成本增加,多个微服务部署多个服务器,数据库

    2.测试难度大,微服务在一定程度上也会导致系统变得越来越复杂,增加集成测试的复杂度

    3.部署工作量大:微服务每个服务都有不同的实例,每个实力都需要配置、部署、监控

    4.作为分布式系统,微服务引入了复杂性和其他若干问题,例如网络延迟、容错性、消息序列化、不可靠网络、异步机制等问题

SpringCloud学习(告别单体架构,步入微服务架构)

个人博客欢迎访问

总结不易,如果对你有帮助,请点赞关注支持一下

本文只展示部分必须代码
详情:完整代码
SpringCloud Config:远程配置中心

目录

文章总览

微服务架构

单体应用架构

什么是单体应用架构

简单的说就是不管啥功能都往一个应用里写,比如电商系统。用户功能、商品功能、订单功能等等,都往一个应用里写

img

微服务架构

微服务架构是一种架构风格,而SpringCloud是实现微服务架构的一系列框架的有序集合

微服务

微服务架构模式是一种将单个应用程序开发为一组小型服务的方法,每个小型服务都在自己的进程中运行并与轻量级机制(通常是HTTP资源API)进行通信。这些服务围绕业务功能构建,并且可以由全自动部署机制独立部署。这些服务的集中管理几乎没有,它可以用不同的编程语言编写并使用不同的数据存储技术。尽管它们的优势使它们在最近几年变得非常时尚,但它们却带来了分销增加,一致性降低的缺点,并且要求运营管理成熟。 -------马丁·福勒

微服务是一个新兴的软件架构,就是把一个大型的单个应用程序和服务拆分为数十个的支持微服务。一个微服务的策略可以让工作变得更为简便,它可扩展单个组件而不是整个的应用程序堆栈,从而满足服务等级协议

简而言之,微服务架构风格,就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API。这些服务围绕业务能力来构建,并通过完全自动化部署机制来独立部署。这些服务使用不同的编程语言书写,以及不同数据存储技术,并保持最低限度的集中式管理

什么是微服务架构

微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅专注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。如果在大规模系统协作下,如何保持系统的稳定性、可快速迭代性就变得非常紧迫。微服务架构便是在这样的历史背景下诞生,提供了一套大型项目开发的解决方案。

img

使用微服务架构的优势和劣势

优势

  • 服务的独立部署:每个服务都是一个独立的项目,可以独立部署,不依赖与其他服务,耦合性低
  • 服务快速启动:拆分之后服务启动速冻必然比拆分之前快很多,因为以来的库少了,代码量也少了
  • 更加适合敏捷开发:敏捷开发以用户的需求进化为核心,采用迭代、循序渐进的方式进行。服务拆分可以快速发布新版本,修改那个版本只需要发布对应的服务即可,不用整体发布
  • 职责专一:由专门的团队负责专门的服务,业务发展迅速,研发人员也会越来越多,每个团队可以负责对应的业务线,服务拆分有利于团队之间的分工
  • 服务可以按需动态扩容:当某个服务的访问量较大时,只需要将这个服务扩容即可
  • 代码复用:每个服务都可以提供REST API,所有的基础服务都必须抽出来,很多底层实现都可以以接口方式提供

劣势

  • 分布式部署,调用复杂性高:单体应用的时候,所有模块之前调用都是在本地进行的,在微服务中,每个模块独立部署,通过HTTP来进行通信这当中会产生很多问题:网络问题、容错问题、调用关系
  • 独立的数据库,分布式事务的挑战:每个微服务都有自己的数据库,这就是所谓的去中心化的数据管理。这种模式的优点在于不同服务,可以选择适合业务自身的数据,比如:订单服务可以使用MySQL、评论服务可以使用MongoDB、商品搜索服务可以用Elasticsearch,缺点就是事务问题了。目前最理想的解决方案就是柔性事务中的最终一致性
  • 测试难度提升:服务和服务之间通过接口交互,当接口改变时,对所有的调用方法都有影响,这是自动化测试就非常重要了,否则人工一个一个测试,工作量就太大了
  • 运维难度的提升:传统的单体中,我们可能只需要关注一个Tomcat的集群、一个MySQL的集群就可以,但这在微服务架构下是行不通的,当业务增加时,服务也将越来越多,服务的部署、监控变得非常负责,这个时候对于运维的要求就高了

微服务架构的四个核心问题

  1. 服务很多,客户端怎么访问
  2. 这么多服务,服务之间如何通信
  3. 这么多服务,如何治理
  4. 服务挂了怎么办

解决方案

SpringCloud生态

  • SpringCloud NetFlix(一站式解决方案)
  • Apache Dubbo Zookeeper(半自动,需要整合)
  • Spring Cloud Alibaba(最新的一站式)

微服务的技术栈

微服务条目落地技术
服务开发SpringBoot、Spring、SpringMVC
服务配置与管理Netflix公司的Archaius、阿里的Diamind等
服务注册与发现Eureka、Consul、Zookeeper等
服务调用Rest、RPC、gRPC
服务熔断器Hystrix、Envoy等
负载均衡Ribbon、Nginx等
服务接口调用(客户端调用服务的简化工具)Feign等
消息队列Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理SpringCloud Config、Chef等
服务路由(API网关)Zuul等
服务监控Zabbix、Nagios、Metrics、Spectator
全链路追踪Zipkin、Brave、Dapper等
服务部署Docker、OpernStack、Kubernetes
数据流操作开发包SpringCloud Stream(封装与Redis,Rabbit,Kafaka等发送接收消息)
事件消息总线Spring Cloud Bus

当前各大IT公司用的微服务架构有哪些?

  • 阿里:dubbo+HFS
  • 京东:JSF
  • 新浪:Motan
  • 当当网 DubboxX

各微服务框架对比

功能点/服务框架Netflix/SpringCloudMotangRPCThriftDubbo/DubboX
功能定位完整的微服务框架RPC框架,但整合了ZK或Consul,实现集群环境的基本服务注册/发现RPC框架RPC框架服务框架
支持Rest是,Ribbon支持多种可插拔的序列化选择
支持RPC是(Hession2)
支持多语言是(Rest形式)?
负载均衡是(服务端zuul+客户端Ribbon),zuul-服务,动态路由,云端负载均衡Eureka(针对中间层服务器)是(客户端)是(客户端)
配置服务Netfix Archaius,Spring Cloud Config Server集中配置是(zookeeper提供)
服务调用链监控是(zuul),zuul提供边缘服务,API网关
高可用/容错是(服务端Hystrix+客户端Ribbon)是(客户端)是(客户端)
典型应用案例NetflixSinaGoogleFacebook
社区活跃程度一般一般2017年后重新开始维护,之前中断了5年
学习难度中等
文档丰富程度一般一般一般
其他Spring Cloud Bus为我们的应用程序带来了更多管理端点支持降级Netflix内部在开发集成gRPCIDL定义实践的公司比较多

SpringCloud概念

目前成熟的互联网架构

应用服务化拆分+消息中间件

image-20210525150144718

为什么需要学习SpringCloud

不论是商业模式和还是用户应用,在业务初期都很简单,我们通常会把它实现为单体结构应用。但是随着业务逐渐发展,产品思想会变得越来越复杂,单体结构的应用会越来越复杂,这就会给应用带来以下问题

  • 代码结构混乱:业务复杂,导致代码量大,管理会越来越难。同时,这也会给业务的快速迭代带来巨大挑战
  • 开发效率变低:开发人员同时开发一套代码,很难避免代码冲突。开发过程会伴随着不断解决冲突的过程,这会严重影响开发效率
  • 排查问题成本高:线上业务发现bug,修复bug的过程可能很简单。但是,由于只有一套代码,需要重新编译、打包、上线、成本很高

由于单体结构的应用随着系统复杂度的增高,会暴露出各种各样的问题。近些年,微服务架构逐渐取代了单体架构,且这种趋势会越来越流行。SpringCloud是目前最常用的微服务开发框架,已经在企业开发中大量应用

什么是SpringCloud

SpringCloud是一系列框架的有序集合。它利用SpringBoot的开发便利性巧妙的化简了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以使用SpringBoot的开发风格做到一键启动和部署,SpringCloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行在封装,屏蔽掉了复杂的配置和实验原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包

SpringCloud的设计目标

协调各个微服务,简化分布式系统开发

微服务的框架:Dubbo、Kubernetes。

特征

  • 分布式/版本化配置
  • 服务注册与发现
  • 路由
  • 服务到服务的通话
  • 负载均衡
  • 断路器
  • 分布式锁
  • 领头选举和集群状态
  • 分布式消息传递

优点:

  • 产出与Spring家族,Spring在企业级开发框架中比例很大,可以保证后续的更新
  • 组件丰富,功能齐全,SpringCloud为微服务架构提供了非常完整的支持,例如:配置管理、服务发现、断路器、微服务网关等
  • Spring Cloud 社区活跃度很高,教程很丰富,遇到问题很容易找到解决方案
  • 服务拆分粒度更细,耦合度比较低,有利于资源重复利用,有利于提高开发效率
  • 可以更精准的制定优化服务方案,提高系统的可维护性
  • 减轻团队的成本,可以并行开发,不用关注其他人怎么开发,先关注自己的开发
  • 微服务可以是跨平台的,可以用任何一种语言开发
  • 适于互联网时代,产品迭代周期更短

缺点:

  • 微服务过多,治理成本高,不利于维护系统
  • 分布式系统开发的成本高(容错,分布式事务等)对团队挑战大

总的来说优点大过于缺点,目前看来Spring Cloud是一套非常完善的分布式框架,目前很多企业开始用微服务、Spring Cloud的优势是显而易见的。因此对于想研究微服务架构的同学来说,学习Spring Cloud是一个不错的选择。

SpringCloud的发展前景

Spring Cloud对于中小型互联网公司来说是一种福音,因为这类公司往往没有实力或者没有足够的资金投入去开发自己的分布式系统基础设施,使用Spring Cloud一站式解决方案能在从容应对业务发展的同时大大减少开发成本。同时,随着近几年微服务架构和Docker容器概念的火爆,也会让Spring Cloud在未来越来越“云”化的软件开发风格中立有一席之地,尤其是在五花八门的分布式解决方案中提供了标准化的、全站式的技术方案,意义可能会堪比当年Servlet规范的诞生,有效推进服务端软件系统技术水平的进步

扩展问题

SpringCloud和Dubbo的区别

DubboSpring Cloud
服务注册中心ZookeeperSpring Cloud Netflix Eureka
服务调用方式RPCREST API
服务监控Dubbo-monitorSpring Boot Admin
断路器不完善Spring Cloud Netflix Hystrix
服务网关Spring Cloud Netflix Zuul
分布式配置Spring Cloud Config
服务跟踪Spring Cloud Sleuth
消息总线Spring Cloud Bus
数据流Spring Cloud Stream
批量任务Spring Cloud Task
  • Dubbo只真针对与服务治理,相当于SpringCloud的一个子集,SpringCloud涉及方方面面,SpringCloud中各种组件应有尽有

  • 性能问题,Dubbo优于SpringCloud,Dubbo基于Netty的TCP及二进制数据传输;SpringCloud基于HTTP,HTTP每次都要创立连接,传输的是文本内容,性能损耗大

  • SpringCloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素

  • Spring Cloud抛弃了RPC通讯,采用基于HTTP的REST方式。Spring Cloud牺牲了服务调用的性能,但是同时也避免了原生RPC带来的问题。REST比RPC更为灵活,不存在代码级别的强依赖,在强调快速演化的微服务环境下,显然更合适。

  • Dubbo像组装机,Spring Cloud像一体机

  • 社区的支持与力度:Dubbo曾经停运了5年,虽然重启了,但是对于技术发展的新需求,还是需要开发者自行去拓展,对于中小型公司,显然显得比较费时费力,也不一定有强大的实力去修改源码

SpringBoot和SpringCloud的区别

  • SpringBoot专注于快速方便的开发单个个体微服务
  • SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整和并管理起来,为各个微服务之间提供配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
  • SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud不能离开SpringBoot,属于依赖的关系
  • SpringBoot专注于快速、方便的开发单体微服务个体;SpringCloud关注全局的服务治理框架

SpringCloud基础

SpringCloud的子项目,大致可以分为两类,一类是对现有成熟框架“SpringBoot化”的封装和抽象,也是数量最多的项目,第二类是开发了一部分分布式系统的基础设施,如SpringCloud Stream扮演的就是Kafka,ActiveMQ这样的角色

SpringCloud Netflix

Netflix OSS 开源组件集成,包括Eureka、Hystrix、Ribbon、Feign、Zuul等核心组件。

  • Eureka:服务治理组件,包括服务端的注册中心和客户端的服务发现机制
  • Ribbon:负载均衡的服务调用组件,具有多种负载均衡调用策略
  • Hystrix:服务容错组件,实现了断路器模式,为依赖服务的出错和延迟提供了容错能力
  • Feign:基于Ribbon和Hystrix的声名式服务调用组件
  • Zuul:API网关组件,对组件提供路由及过滤功能

REST

REST是什么

REST的英文是Representational State Transfer,中文翻译”表述性状态转移“,一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

REST的设计准则
  1. 网络上的所有事物都被抽象为资源(resource)
  2. 每个资源对应一个唯一的资源标识符(resource identifier)
  3. 通过通用的连接器接口(generic connector interface)对资源进行操作;
  4. 对资源的各种操作不会改变资源标识符
  5. 所有的操作都是无状态的(stateless)

使用RESTful操作资源

【GET】 /users # 查询用户信息列表

【GET】 /users/1001 # 查看某个用户信息

【POST】 /users # 新建用户信息

【PUT】 /users/1001 # 更新用户信息(全部字段)

【PATCH】 /users/1001 # 更新用户信息(部分字段)

【DELETE】 /users/1001 # 删除用户信息

API设计风格基本规则

RestTemplate

RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多重便捷访问远程HTTP服务的方,能够大大提高客户端的编码效率

创建RestTemplate对象
/**
 * @author :zsy
 * @date :Created 2021/5/25 20:27
 * @description:配置RestTemplate
 */
@Configuration
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
getForObject

url:请求的地址,两种方式,其中一种是字符串,另一种是URI

responseType:返回值类型

uriVariables:有两种方式,其中一种是可变长参数,另一种是Map形式

@Override
@Nullable
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
	RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
	HttpMessageConverterExtractor<T> responseExtractor =
			new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
	return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
@Override
@Nullable
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
	RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
	HttpMessageConverterExtractor<T> responseExtractor =
			new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
	return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
@Override
@Nullable
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
	RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
	HttpMessageConverterExtractor<T> responseExtractor =
			new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
	return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
}
getForEntity

不同与getForObject,getForEntity可以获取返回的状态码、请求头信息,通过getBoby获取响应内容,其余的和getForObject一样

@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
		throws RestClientException {
	RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
	ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
	return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
		throws RestClientException {
	RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
	ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
	return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
@Override
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
	RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
	ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
	return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor));
}
PostForObject

使用post的方式调用接口

@Override
@Nullable
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
		Object... uriVariables) throws RestClientException {
	RequestCallback requestCallback = httpEntityCallback(request, responseType);
	HttpMessageConverterExtractor<T> responseExtractor =
			new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
	return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
@Nullable
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
		Map<String, ?> uriVariables) throws RestClientException {
	RequestCallback requestCallback = httpEntityCallback(request, responseType);
	HttpMessageConverterExtractor<T> responseExtractor =
			new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
	return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
@Nullable
public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType)
		throws RestClientException {
	RequestCallback requestCallback = httpEntityCallback(request, responseType);
	HttpMessageConverterExtractor<T> responseExtractor =
			new HttpMessageConverterExtractor<>(responseType, getMessageConverters());
	return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
}

除了get、post的方法外,RestTemplate还提供了put、delete等操作,还有一个比较使用的exchange操作,可以同时执行get、post、put、delete四种请求方式

Eureka

概念

服务注册与发现

Eureka是Netflix的一个子模块,也是核心模块之一,Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务的发现和故障转移。服务注册和发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,ZooKeeper

原理

系统中的服务使用Eureka的客户端连接到Eureka Server并维持心跳连接,这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行,SpringCloud的一些其他模块(例如Zuul)可以通过Eureka Server来发现系统中的其他微服务,并执行相关逻辑

Eureka中包含两大组件

  • Eureka server:节点启动后,会在Eureka Server中进行注册, 这样Eureka server中的服务注册表中将会村粗所有可用服务节点的信息,节点信息可以在界面中直观的看到
  • Eureka client:用户简化Eureka server的交互,客户端也具备一个内置的、轮询负载算法的负载均衡器,在启动后,将会向Eureka server发送心跳(默认周期为30s),如果Eureka server在多个心跳周期内没有收到某节点的心跳,Eureka server将会从服务注册表中将这个节点移除

三大角色:

  • Eureka server:提供服务的注册和发现
  • Service Provider:服务提供方将自身的服务注册到Eureka server中,从而使服务消费方能够找到
  • Service Consumer:服务方从Eureka server中获取注册服务列表,从而能够小消费服务

什么是自我保护模式

默认情况下,如果Eureka server在一定时间没有收到某个微服务实例的心跳,Eureka server将会注销该实例(90s后),但是当网络分区发生故障,微服

以上是关于面试遇到的,总结一下,欢迎指正:单体架构跟微服务架构的选择以及优缺点的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud学习(告别单体架构,步入微服务架构)

2021面试总结Android 鸡架面试题&基础架构组涉及的sdk相关面试题

微服务架构详解

微服务架构之演进历程

8000 字详解微服务架构

一文全解微服务架构知识