优点:通过服务的原子化拆分,以及微服务的独立打包、部署和升级,小团队的交付周期将缩短,运维成本也将大幅度下降,微服务遵循单一原则。微服务之间采用Restful等轻量协议传输。
缺点:微服务过多,服务治理成本高,不利于系统维护。分布式系统开发的技术成本高(容错、分布式事务等)。
我们知道,两个springboot项目如果放在同一台主机上运行,那么我们可以通过HttpClient或者Okhttp等等方式去创建一个Http客户端实现由这一个springboot项目去访问另一个springboot项目的过程,那么如果这两个项目不在同一个主机上呢?在局域网中?在公网中?其实大同小异,只要我们能够通过http协议的方式远程访问到对应的API接口就可以实现两个项目之间的调用。这就是一次远程调用,当然这里指的是基于Http的远程调用方式。
在微服务架构中,通常存在多个服务之间的远程调用的需求。远程调用通常包含两个部分:序列化和通信协议。常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等,目前主流的远程调用技术有基于HTTP的RESTFUL接口以及基于TCP的RPC协议。
REST,即Representational State Transfer的缩写,如果一个架构符合REST原则,就称它为RESTful架构。
资源
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资 源"(Resources)的"表现层"。
表现层
"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。
状态转化
访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。综合上面的解释,我们总结一下什么是RESTful架构:每一个URI代表一种资源;客户端和服务器之间,传递这种资源的某种表现层;客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。
RPC(Remote Procedure Call ) 一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式(TCP或者UDP)、序列化方式(XML/JSON/二进制)和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。RPC 框架作为架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率,屏蔽跨进程调用函数(服务)的各类复杂细节。让调用方感觉就像调用本地函数一样调用远端函数、让服务提供方感觉就像实现一个本地函数一样来实现服务。
任何情况下一个分布式架构系统下CAP三者只能满足其中两个。
springcloud是常见的微服务框架之一,作为spring家族的金字塔尖,它并不是一项新的项目,而是集成市面上大部分的分布式微服务工程中优质的项目,具备各种优秀的组件使得在一个微服务工程中程序员可以直接通过springcloud这一个包去调用各种优质的jar包。
服务注册:服务实例将自身服务信息注册到注册中心。这部分服务信息包括服务所在主机IP和提供服务的Port,以及暴露服务自身状态以及访问协议等信息。
服务发现:服务实例请求注册中心获取所依赖服务信息。服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务。
负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性
熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪
随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现:
针对这些问题,API网关顺势而生。API网关直面意思是将所有API调用统一接入到API网关层,由网关层统一接入和输出。一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。
构想一下思路:我们建立同一个父工程remote_call下的两个子模块server_a与server_b,要将两个子模块跑起来,之后利用server_b模块去调用server_a的一个API接口并获取它的返回信息展示在页面上,server_b 去通信 server_a 的方法不限,我这里采取RestTemplate这个spring为我们封装好的Http客户端工具。
1、创建父工程remote_call模块
只需要配置它的pom文件即可,这里我的remote_call模块的父工程已经将用到的SpringBoot依赖都导入且统一管理了。
remote_call
spring_cloud
org.example
1.0-SNAPSHOT
4.0.0
remote_call
pom
server_a
17
17
spring_cloud(后面的测试都是要用这个作为父模块)
4.0.0
org.example
spring_cloud
pom
1.0-SNAPSHOT
product
eureka
order
remote_call
spring-boot-starter-parent
org.springframework.boot
2.6.7
17
17
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-test
org.projectlombok
lombok
1.18.24
provided
org.springframework.cloud
spring-cloud-dependencies
2021.0.3
pom
import
spring-snapshots
Spring Snapshots
http://repo.spring.io/libs-snapshot-local
true
spring-milestones
Spring Milestones
http://repo.spring.io/libs-milestone-local
false
spring-releases
Spring Releases
http://repo.spring.io/libs-release-local
false
spring-snapshots
Spring Snapshots
http://repo.spring.io/libs-snapshot-local
true
spring-milestones
Spring Milestones
http://repo.spring.io/libs-milestone-local
false
org.springframework.boot
spring-boot-maven-plugin
2、创建子模块server_a
1、pom文件
remote_call
org.example
1.0-SNAPSHOT
4.0.0
server_a
17
17
2、application.yml
server:
port: 9001
spring:
application:
name: server_a
3、启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class server_a_ApplicationStarter {
public static void main(String[] args) {
SpringApplication.run(server_a_ApplicationStarter.class,args);
}
}
4、controller
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("server_a")
public class controller {
@RequestMapping(value = "sendMessageToServerB",method = RequestMethod.GET)
@ResponseBody
public String sendMessage(){
return "hello,server_b! i am server_a";
}
}
3、创建子模块server_b
1、pom文件
remote_call
org.example
1.0-SNAPSHOT
4.0.0
server_b
17
17
2、application.yml
server:
port: 9002
spring:
application:
name: server_b
3、启动类
@SpringBootApplication
public class server_b_ApplicationStarter {
@Bean
public RestTemplate RestTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(server_b_ApplicationStarter.class,args);
}
}
4、controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("server_b")
public class controller {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "remote_server_a",method = RequestMethod.GET)
public String remoteCallServerA(){
return restTemplate.getForObject("http://127.0.0.1:9001/server_a/sendMessageToServerB",String.class);
}
}
4、测试结果:
访问http://localhost:9002/server_b/remote_server_a得到结果如下:
5、总结:
成功实现两个模块之间的远程调用,那么这种方式我是通过这样一行代码实现的:
restTemplate.getForObject("http://127.0.0.1:9001/server_a/sendMessageToServerB",String.class);
我们不难发现其中的地址信息是硬编码,后续如果server_a这个模块挂掉了,就算它有别的结点服务,我也访问不到了,能不能有一个通讯录记录这个微服务的电话呢?因为我们知道分布式架构的多结点特性是它高可用性的体现依赖,那么一个微服务可能出现在多个主机结点中运行,挂了一个我们还能够使用别的结点中的这一块微服务。但是如果没有一个中间的通讯录,采取硬编码的方式,显然无法实现这样一个系统的需求。于是,优质的程序员们设计出了服务注册中心这一个概念。