首页 > 其他分享 >深入探讨微服务架构中的同步通信机制

深入探讨微服务架构中的同步通信机制

时间:2024-08-09 09:38:27浏览次数:3  
标签:负载 同步 服务 HTTP 深入探讨 RestTemplate 架构 客户端 String

微服务架构是一种设计方法,将应用程序划分为一组小型服务,每个服务在独立的进程中运行,通常根据业务能力进行组织。这些服务通过多种通信方式交互,以实现整个应用的功能。今天我们着重介绍同步通信,关于异步通信和消息队列(MQ)等内容将在后续讲解。

这里所指的通信,是指我们在客户端内部进行的服务间通信,而非通过调用外部的Web服务进行访问。好的,让我们开始。

负载均衡

服务端负载均衡

在深入探讨客户端负载均衡之前,我们首先应该对服务端负载均衡有一个更加深入的了解,例如nginx组件。现在让我们来仔细看一下:

image

nginx通常用来对我们服务器内部进行负载转发请求,而客户端则是在各个服务内部进行负载分担。

客户端负载均衡

在Spring Cloud中,例如使用Ribbon时,客户端会维护一个服务器地址列表,在发送请求之前通过负载均衡算法选择一个服务器进行访问。这种方式被称为客户端负载均衡,因为它在客户端内部就完成了负载均衡算法的分配工作。

image

同步通信

一般情况下,我们在进行HTTP请求时常会借助各种工具类。我相信大家之前可能经常自行封装httputils等类,或者使用其他官方提供的工具。比如,今天我们来讲解一下RestTemplate工具类。它其实就是一个用来发送HTTP请求的工具,只不过它在此基础上多做了一些额外的工作。接下来我们先看一下它的基本用法。

RestTemplate

RestTemplate 是由 Spring 框架提供的一个功能强大的类,专门用于进行同步客户端的 HTTP 访问。它的设计旨在简化使用 HTTP 客户端进行 REST 调用的复杂流程,并提供了丰富的方法和功能来处理各种 HTTP 请求和响应。

创建 RestTemplate 实例

首先,你需要创建一个 RestTemplate 的实例。这可以通过直接实例化或使用Spring的自动装配来完成。

import org.springframework.web.client.RestTemplate;

RestTemplate restTemplate = new RestTemplate();

发送请求

使用 RestTemplate 发送一个GET请求并获取响应体。

String url = "http://example.com/api/resource";
String result = restTemplate.getForObject(url, String.class);
System.out.println(result);

发送一个POST请求,通常包含请求体。

String url = "http://example.com/api/resource";
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("key1", "value1");
requestMap.put("key2", "value2");

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestMap, headers);
String response = restTemplate.postForObject(url, entity, String.class);
System.out.println(response);

看到这里,你可能会想到,这与微服务间的通信有什么关系呢?难道不只是简单的 HTTP 调用吗?让我们继续深入探讨。

LoadBalanced注解

微服务架构中通常会涉及到注册中心。今天我们专注讨论微服务间的通信,而不深入讲解注册中心,例如 Nacos 是如何管理所有微服务的注册以及如何使一个服务节点发现其他服务节点的。假设我们已经获得了其他服务节点的 IP 地址,你可能会想直接将上述示例中的域名替换为 IP 地址,但是在面对保证高可用的多节点微服务时,直接在代码中写死 IP 地址将会带来灾难性的后果。所有的 IP 地址应当由一个统一组件进行管理和选择。

因此,Ribbon应运而生。一般情况下,如果在项目的pom文件中集成了Nacos依赖,通常会默认包含Ribbon组件,因此不需要单独配置pom文件来引入Ribbon依赖。

基本用法

如前所述,一种方法是直接实例化对象,另一种则是通过Spring容器进行管理和注入。

@Configuration
public class RestConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

这样一来,当需要使用时,就可以轻松地进行服务调用操作。

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/findOrderByUserId/{id}")
    public R findOrderByUserId(@PathVariable("id") Integer id) {
        String url = "http://mall-order/order/findOrderByUserId/"+id;
        R result = restTemplate.getForObject(url,R.class);
        return result;
    }
}

注意,mall-order可不是我们说的网站域名,而是我们配置在nacos等注册中心的服务名。

添加了LoadBalanced注解后,RestTemplate会自动注入所需的依赖项,具体的实现可以通过查看源代码来了解。

源码分析

关于Spring的自动配置,我之前在讲解Spring时提到过很多次,这里就不再详细展开了。我们可以看到它实现了SmartInitializingSingleton接口,因此,想要使用负载均衡功能,必须等到所有的bean都加载完毕才能进行。

image

好的,我们可以看到,在这里他向RestTemplate类添加了一个拦截器。接下来,我们可以探究一下这个拦截器具体做了什么。我选择不逐步展示整个过程是因为这并不必要。首先,这样做记不住,其次,就像处理业务一样,我们只关注最终走到了哪一个数据表。我们只需记住他一定会经过的那个十字路口即可,这样可以减轻大脑的负担。

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
            final ClientHttpRequestExecution execution) throws IOException {
        final URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null,
                "Request URI does not contain a valid hostname: " + originalUri);
        return this.loadBalancer.execute(serviceName,
                this.requestFactory.createRequest(request, body, execution));
    }

其实,看到这一点,不用猜也能明白。一旦获取了serviceName,也就是我们之前定义的微服务名,它会在execute方法中被替换为真正的IP地址,然后最终调用HTTP请求完成整个过程。让我们来仔细看一下源代码吧。

    public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
            throws IOException {
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        Server server = getServer(loadBalancer, hint);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        }
        RibbonServer ribbonServer = new RibbonServer(serviceId, server,
                isSecure(server, serviceId),
                serverIntrospector(serviceId).getMetadata(server));

        return execute(serviceId, ribbonServer, request);
    }

所有的负载均衡规则都实现在getServer方法中,我们不再深入追踪了。在这一步,我们已经找到了要调用的微服务。如果你还有疑问,我们可以看一下Server类的具体实现,就能明白了。

image

最终就交给HTTP调用即可。然而,仅仅这样还不够。难道你会愿意在每个服务中编写这种无关紧要的服务调用代码吗?这会非常繁琐,不仅增加了业务逻辑的复杂性,还让人感到不便。幸运的是,有了Spring Cloud OpenFeign,这一切变得轻松许多。OpenFeign的出现正是为了解决这种服务间通信的问题,它将这些繁琐的细节封装起来。

然而,要注意,这种封装并不影响通信的实质。下次我们将详细讨论Spring Cloud OpenFeign与Dubbo调用组件的区别与使用方法。

总结

今天我们专注于微服务之间的网络通信。可以清楚地看到,框架的最终目标是使程序员能够更专注于业务逻辑,而不是被迫写各种无关紧要的代码。总结一下,尽管我们使用了框架和各种抽象,但最终仍然是通过HTTP来进行调用。不同的是,在实际调用之前,我们引入了一个拦截器来实现微服务的负载均衡。这个拦截器中实现了各种均衡算法,最终确定真实的IP地址和端口,以便进行访问并获取所需的数据。


我是努力的小雨,一名 Java 服务端码农,潜心研究着 AI 技术的奥秘。我热爱技术交流与分享,对开源社区充满热情。同时也是一位掘金优秀作者、腾讯云内容共创官、阿里云专家博主、华为云云享专家。

标签:负载,同步,服务,HTTP,深入探讨,RestTemplate,架构,客户端,String
From: https://www.cnblogs.com/guoxiaoyu/p/18345043

相关文章

  • 甄选范文“论数据湖技术及其应用”软考高级论文系统架构设计师论文
    论文真题请围绕“数据湖技术及其应用”论题,依次从以下三个方面进行论述。1.概要叙述你所参与管理或开发的软件项目,以及你在其中所承担的主要工作。2.详细阐述数据湖技术,并从主要数据来源、数据模式(Schema)转换时机、数据存储成本、数据质量、面对用户和主要支撑应用类型......
  • 论软件设计方法及其应写作框架软考高级论文系统架构设计师论文
    论文真题软件设计(SoftwareDesign,SD)根据软件需求规格说明书设计软件系统的整体结构、划分功能模块、确定每个模块的实现算法以及程序流程等,形成软件的具体设计方案。软件设计把许多事物和问题按不同的层次和角度进行抽象,将问题或事物进行模块化分解,以便更容易解决问题。......
  • 甄选范文“论软件设计方法及其应”软考高级论文系统架构设计师论文
    论文真题软件设计(SoftwareDesign,SD)根据软件需求规格说明书设计软件系统的整体结构、划分功能模块、确定每个模块的实现算法以及程序流程等,形成软件的具体设计方案。软件设计把许多事物和问题按不同的层次和角度进行抽象,将问题或事物进行模块化分解,以便更容易解决问题。......
  • MVC、三层架构、分页
    一、MVC什么是MVC?MVC全名是ModelViewController,是模型(Model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。最简单、......
  • 在淘客返利系统中实现多租户架构与管理
    在淘客返利系统中实现多租户架构与管理大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!随着淘客返利系统的不断发展,支持多租户架构已经成为一种趋势。多租户架构允许多个租户(客户)共享同一个系统,但每个租户的数据是相互隔离的。本文将详细介绍如......
  • 大模型核心技术原理 Transformer架构详解
    在大模型发展历程中,有两个比较重要点:第一,Transformer架构。它是模型的底座,但Transformer不等于大模型,但大模型的架构可以基于Transformer;第二,GPT。严格意义上讲,GPT可能不算是一个模型,更像是一种预训练范式,它本身模型架构是基于Transformer,但GPT引入了“预测下一个词......
  • 京东小程序数据中心架构设计与最佳实践
    一、京东小程序是什么京东小程序平台能够提供开放、安全的产品,成为品牌开发者链接京东内部核心产品的桥梁,致力于服务每一个信任我们的外部开发者,为不同开发能力的品牌商家提供合适的服务和产品,让技术开放成为品牌的新机会。“OnceBuild,RunAnywhere”,一个小程序可以在多个A......
  • 架构师与普通程序员的区别
    引言在软件开发行业中,架构师和普通程序员是两个重要但角色和职责截然不同的职位。本文将深入探讨架构师和普通程序员的区别,包括他们的职责、技能要求、工作方式以及职业发展路径。一、架构师的角色和职责1.系统设计和架构架构师主要负责系统的整体设计和架构,他们需要制定......
  • 计算机毕业设计-基于Java+SSM架构的珠宝首饰交易平台系统项目开发实战(附源码+论文)
    大家好!我是程序员一帆,感谢您阅读本文,欢迎一键三连哦。......
  • 【线程同步机制】Day13线程同步:互斥锁、条件变量、自旋锁、读写锁
    进程间通信详解,移步:https://blog.csdn.net/Thmos_vader/article/details/140743256线程同步对于一个单线程进程来说,不需要处理线程同步的问题,所以线程同步是在多线程环境下是需要注意的一个问题。线程的主要优势在于,资源的共享性,譬如通过全局变量来实现信息共享,不过这种......