暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【微服务】微服务间通信的最佳实践

超级架构师 2023-05-26
236

一个好的 API 架构对于有效处理微服务之间的通信很重要。不要害怕创建新的微服务,并尽可能地尝试解耦功能。例如,与其创建一个通知服务,不如尝试为电子邮件通知、SMS 通知和移动推送通知创建单独的微服务。
在这里,我假设您有一个 API 网关来管理请求、处理到负载平衡服务器的路由并限制未经授权的访问。

通讯类型

 

  • 同步协议:HTTP 是一种同步协议。客户端发送请求并等待服务的响应。这与客户端代码执行无关,它可以是同步的(线程被阻塞)或异步的(线程未被阻塞,并且响应最终会到达回调)。这里的重点是协议(HTTP/HTTPS)是同步的,客户端代码只有在收到 HTTP 服务器响应后才能继续其任务。

  • 异步协议:其他协议如 AMQP(许多操作系统和云环境支持的协议)使用异步消息。客户端代码或消息发送者通常不等待响应。它只是将消息发送到消息代理服务,例如 RabbitMQ 或 Kafka(如果我们使用的是事件驱动架构)。


为什么你应该避免同步协议

 

  • 如果您不断添加相互通信的新微服务,那么在代码中使用端点会造成混乱,尤其是当您必须在端点中传递额外信息时。例如,身份验证令牌。

  • 您必须等待耗时的调用才能获得响应。

  • 如果响应失败并且您有重试策略,那么它可能会造成瓶颈。

  • 如果接收器服务关闭或无法处理请求,那么我们要等到服务启动。例如,在电子商务网站中,用户下订单并请求发送到发货服务以发货,但发货服务关闭,我们丢失了订单。一旦完成,如何将相同的订单发送到运输服务?

  • 接收方可能无法一次处理大量请求,因此应该有一个地方让请求必须等待,直到接收方准备好处理下一个请求。

为了应对这些挑战,我们可以使用一个中间服务来处理两个微服务之间的通信,也称为“消息代理”。
RabbitMQ 被广泛用作消息代理服务,如果您将 Azure 云作为托管服务提供商,您也可以使用 Azure 服务总线。


如何使用RabbitMQ来处理微服务之间的通信

可能存在发件人想要向多个服务发送消息的情况。让我们看看 RabbitMQ 如何处理的下图。

当发布者发送消息时,它被 Exchange 接收,然后 Exchange 将其发送到目标队列。消息保持在队列中,直到接收方接收并处理它。


交换类型

 

  • 直接交换根据消息路由键将消息传递到队列。这是默认的交换类型。

  • 扇出交换将消息传递到所有队列。

  • Header Exchange 根据消息头标识目标队列。

  • 主题交换类似于直接交换,但路由是根据路由模式完成的。它不使用固定的路由键,而是使用通配符。

例如,假设我们有以下路由模式。

  • order.logs.customer

  • order.logs.international

  • order.logs.customer.electronics

  • order.logs.international.electronics


“order.*.*.electronics” 的路由模式只匹配第一个词是“order”,第四个词是“electronics”的路由键。
“order.logs.customer.#”的路由模式匹配任何以“order.logs.customer”开头的路由键。


实现RabbitMQ


安装


按照此链接在 Windows 上安装 RabbitMQ。安装后 RabbitMQ 服务将在 http://localhost:15672/ 上启动并运行。在用户名和密码中输入“guest”登录,您将能够看到所有静态信息。

创建发件人服务


RabbitMQ 启动并运行后,创建两个控制台应用程序
Sender:向RabbitMQ发送消息
Receiver:从RabbitMQ接收消息
向两个应用程序添加包“RabbitMQ.Client”。

using System;
using RabbitMQ.Client;
using System.Text;

class Send
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello", durable: false, exclusive: false,
autoDelete: false, arguments: null);

string message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message);

channel.BasicPublish(exchange: "", routingKey: "hello",
basicProperties: null, body: body);
Console.WriteLine(" [x] Sent {0}", message);
}

Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}

上面的代码将创建一个到 RabbitMQ 的连接,创建一个队列“hello”并向队列发布一条消息。

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;

class Receive
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello", durable: false,
exclusive: false, autoDelete: false, arguments: null);

Console.WriteLine(" [*] Waiting for messages.");

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
};
channel.BasicConsume(queue: "hello", autoAck: true, consumer: consumer);

Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}

上面的代码将创建一个到 RabbitMQ 的连接,创建一个队列(如果它还没有创建),并注册一个将接收和处理消息的处理程序。

在运行发送方和接收方应用程序时,您将能够看到在 RabbitMQ 门户上创建的队列,以及表示收到新消息的图形上的尖峰。从门户中,您将能够看到哪个服务有待处理的消息,您可以添加该服务的另一个实例以进行负载平衡。
一开始你可以使用rabbitMQ,事情会很顺利。但是当复杂性增加并且您有很多端点调用其他服务时,它就会造成混乱。很快,您会发现自己围绕驱动程序创建了一个包装器,这样您就可以减少需要编写的代码量。例如,每次您调用另一个服务的端点时,您都必须提供身份验证令牌。然后你会发现自己需要处理 ack 与 nack,你将为此创建一个简单的 API。最终,您将需要处理有害消息——格式错误并导致异常的消息。
要处理所有这些工作流,您可以使用 NserviceBus。让我们讨论一个项目结构:

考虑到这种架构,ClientUI 端点将 PlaceOrder 命令发送到 Sales 端点。因此,Sales 端点将使用发布/订阅模式发布 OrderPlaced 事件,该事件将由 Billing 端点接收。
NserviceBus 配置:

class Program
{
static async Task Main(string[] args)
{
await CreateHostBuilder(args).RunConsoleAsync();
}

public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseNServiceBus(context =>
{
var endpointConfiguration = new EndpointConfiguration("Sales");

configure transport - configure where your message will
  be published/saved
you can configure it for RabbitMq, Azure Queue, Amazon
  SQS or any other cloud provider
endpointConfiguration.UseTransport<LearningTransport>();

endpointConfiguration.SendFailedMessagesTo("error");
When a message fails processing
it will be forwarded here.
endpointConfiguration.AuditProcessedMessagesTo("audit");
All messages received by an endpoint
  will be forwarded to the audit queue.

return endpointConfiguration;
});
}
}

然后使用 IMessageSession 对象发送消息:

public class HomeController : Controller
{
static int messagesSent;
private readonly ILogger<HomeController> _log;
private readonly IMessageSession _messageSession;

public HomeController(IMessageSession messageSession, ILogger<HomeController> logger)
{
_messageSession = messageSession;
_log = logger;
}

[HttpPost]
public async Task<ActionResult> PlaceOrder()
{
string orderId = Guid.NewGuid().ToString().Substring(0, 8);

var command = new PlaceOrder { OrderId = orderId };

Send the command
await _messageSession.Send(command)
.ConfigureAwait(false);

_log.LogInformation($"Sending PlaceOrder, OrderId = {orderId}");

dynamic model = new ExpandoObject();
model.OrderId = orderId;
model.MessagesSent = Interlocked.Increment(ref messagesSent);

return View(model);
}
}

最后,添加一个处理程序来接收和处理消息:

public class PlaceOrderHandler :
IHandleMessages<PlaceOrder>
{
static readonly ILog log = LogManager.GetLogger<PlaceOrderHandler>();
static readonly Random random = new Random();

public Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
log.Info($"Received PlaceOrder, OrderId = {message.OrderId}");

return Task.CompletedTask;
}
}

这是 NserviceBus 和 RabbitMQ 的基本实现。


概括


在服务之间通信时避免使用同步协议。使用 RabbitMQ 在服务之间进行通信并在消息从源传送到目标之前临时保存它们。使用 NserviceBus 解耦应用程序代码和消息代理,并管理长时间运行的请求。


本文 :https://architect.pub/best-practices-communicate-between-microservices
讨论:知识星球【首席架构师圈】或者加微信小号【ca_cto】或者加QQ群【792862318
公众号

【jiagoushipro】
【超级架构师】
精彩图文详解架构方法论,架构实践,技术原理,技术趋势。
我们在等你,赶快扫描关注吧。
微信小号

【ca_cea】
50000人社区,讨论:企业架构,云计算,大数据,数据科学,物联网,人工智能,安全,全栈开发,DevOps,数字化.

QQ群

【285069459】深度交流企业架构,业务架构,应用架构,数据架构,技术架构,集成架构,安全架构。以及大数据,云计算,物联网,人工智能等各种新兴技术。
加QQ群,有珍贵的报告和干货资料分享。


视频号超级架构师
1分钟快速了解架构相关的基本概念,模型,方法,经验。
每天1分钟,架构心中熟。


知识星球【首席架构师圈】向大咖提问,近距离接触,或者获得私密资料分享。

喜马拉雅超级架构师路上或者车上了解最新黑科技资讯,架构心得。【智能时刻,架构君和你聊黑科技】
知识星球认识更多朋友,职场和技术闲聊。知识星球【职场和技术】
领英Harryhttps://www.linkedin.com/in/architect-harry/
领英群组领英架构群组
https://www.linkedin.com/groups/14209750/
微博超级架构师智能时刻
哔哩哔哩超级架构师

抖音【cea_cio】超级架构师

快手【cea_cio_cto】超级架构师


小红书【cea_csa_cto】超级架构师

网站CIO(首席信息官)https://cio.ceo
网站CIO,CTO和CDOhttps://cioctocdo.com
网站架构师实战分享https://architect.pub   
网站程序员云开发分享https://pgmr.cloud
网站首席架构师社区https://jiagoushi.pro
网站应用开发和开发平台https://apaas.dev
网站开发信息网https://xinxi.dev
网站超级架构师https://jiagou.dev
网站企业技术培训https://peixun.dev
网站程序员宝典https://pgmr.pub    
网站开发者闲谈https://blog.developer.chat
网站CPO宝典https://cpo.work
网站首席安全官https://cso.pub    
网站CIO酷https://cio.cool
网站CDO信息https://cdo.fyi
网站CXO信息https://cxo.pub
谢谢大家关注,转发,点赞和点在看。


文章转载自超级架构师,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论