RabbitMq - ConversationId 与 CorrelationId - 哪个更适合跟踪特定请求?

2024-02-05

RabbitMQ 似乎有两个非常相似的属性,我并不完全理解其中的区别。ConversationId and CorrelationId.

我的用例如下。我有一个网站,可以生成Guid。该网站调用 API,将该唯一标识符添加到HttpRequest标头。这又会向 RabbitMQ 发布一条消息。该消息由第一个消费者处理,然后传递给其他消费者,依此类推。

出于记录目的,我想记录一个将初始请求与所有后续操作联系在一起的标识符。对于整个应用程序不同部分的旅程来说,这应该是唯一的。因此。当记录到像 Serilog/ElasticSearch 这样的东西时,就可以很容易地看到哪个请求触发了初始请求,并且整个应用程序中该请求的所有日志条目都可以关联在一起。

我创建了一个提供者来查看传入的HttpRequest为标识符。我将其称为“CorrelationId”,但我开始怀疑这是否真的应该命名为“ConversationId”。就 RabbitMQ 而言,“ConversationId”的想法更适合该模型,还是“CorrelationId”更好?

这两个概念有什么区别?

在代码方面,我希望执行以下操作。首先在我的API中注册总线并配置SendPublish使用CorrelationId来自提供商。

// bus registration in the API
var busSettings = context.Resolve<BusSettings>();
// using AspNetCoreCorrelationIdProvider
var correlationIdProvider = context.Resolve<ICorrelationIdProvider>();

var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    cfg.Host(
        new Uri(busSettings.HostAddress),
        h =>
        {
            h.Username(busSettings.Username);
            h.Password(busSettings.Password);
        });
    cfg.ConfigurePublish(x => x.UseSendExecute(sendContext =>
    {
        // which one is more appropriate
        //sendContext.ConversationId = correlationIdProvider.GetCorrelationId();
        sendContext.CorrelationId = correlationIdProvider.GetCorrelationId();
    }));
});

作为参考,这是我的简单提供者界面

// define the interface
public interface ICorrelationIdProvider
{
    Guid GetCorrelationId();
}

以及 AspNetCore 实现,它提取调用客户端(即网站)设置的唯一 ID。

public class AspNetCoreCorrelationIdProvider : ICorrelationIdProvider
{
    private IHttpContextAccessor _httpContextAccessor;

    public AspNetCoreCorrelationIdProvider(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public Guid GetCorrelationId()
    {
        if (_httpContextAccessor.HttpContext.Request.Headers.TryGetValue("correlation-Id", out StringValues headers))
        {
            var header = headers.FirstOrDefault();
            if (Guid.TryParse(header, out Guid headerCorrelationId))
            {
                return headerCorrelationId;
            }
        }

        return Guid.NewGuid();
    }
}

最后,我的服务主机是简单的 Windows 服务应用程序,它们坐着并使用已发布的消息。他们使用以下内容来获取 CorrelationId,并且很可能会发布给其他消费者以及其他服务主机中的其他消费者。

public class MessageContextCorrelationIdProvider : ICorrelationIdProvider
{
    /// <summary>
    /// The consume context
    /// </summary>
    private readonly ConsumeContext _consumeContext;

    /// <summary>
    /// Initializes a new instance of the <see cref="MessageContextCorrelationIdProvider"/> class.
    /// </summary>
    /// <param name="consumeContext">The consume context.</param>
    public MessageContextCorrelationIdProvider(ConsumeContext consumeContext)
    {
        _consumeContext = consumeContext;
    }

    /// <summary>
    /// Gets the correlation identifier.
    /// </summary>
    /// <returns></returns>
    public Guid GetCorrelationId()
    {
        // correlationid or conversationIs?
        if (_consumeContext.CorrelationId.HasValue && _consumeContext.CorrelationId != Guid.Empty)
        {
            return _consumeContext.CorrelationId.Value;
        }

        return Guid.NewGuid();
    }
}

然后,我的消费者中有一个记录器,它使用该提供程序来提取CorrelationId:

public async Task Consume(ConsumeContext<IMyEvent> context)
{
    var correlationId = _correlationProvider.GetCorrelationId();
    _logger.Info(correlationId, $"#### IMyEvent received for customer:{context.Message.CustomerId}");

    try
    {
        await _mediator.Send(new SomeOtherRequest(correlationId) { SomeObject: context.Message.SomeObject });
    }
    catch (Exception e)
    {
        _logger.Exception(e, correlationId, $"Exception:{e}");
        throw;
    }

    _logger.Info(correlationId, $"Finished processing: {DateTime.Now}");
}

正在阅读docs http://masstransit-project.com/MassTransit/usage/correlation.html,它对“ConversationId”说了以下内容:

对话由发送的第一条消息创建或 已发布,其中没有可用的现有上下文(例如当 消息通过使用 IBus.Send 或 IBus.Publish 发送或发布)。如果 现有上下文用于发送或发布消息, ConversationId 被复制到新消息中,确保一组 同一对话中的消息具有相同的标识符。

现在我开始认为我的术语混淆了,从技术上讲,这是一次对话(尽管“对话”就像“电话游戏”)。

So, CorrelationId在此用例中,或ConversationId?请帮助我正确理解我的术语!!


在消息对话(提示不祥的乐谱)中,可以有一条消息(我告诉你做某事,或者我告诉每个正在听的人发生了什么事)或多个消息(我告诉你做某事,你告诉其他人,或者我告诉每个正在听的人发生了一些事情,这些听众告诉他们的朋友,等等,等等)。

使用 MassTransit,从第一条消息到最后一条消息,如果使用得当,这些消息中的每一条都会有相同的ConversationId。 MassTransit 从以下位置复制属性ConsumeContext,未经修改,在消息消费期间每条传出消息。这使得一切都变得相同trace- 一个对话。

但是,MassTransit 默认情况下不会设置 CorrelationId。如果消息属性名为 CorrelationId(或 CommandId 或 EventId),则可以自动设置它,或者您也可以添加自己的名称。

如果 CorrelationId 出现在使用的消息上,则任何传出消息都会将该 CorrelationId 属性复制到 InitiatorId 属性(原因和结果 - 使用的消息启动了后续消息的创建)。这形成了一条链(或跟踪术语中的跨度),可以遵循该链来显示从初始消息开始的消息传播。

CorrelationId 应被视为命令或事件的标识符,以便可以在整个系统日志中看到该命令的效果。

在我看来,您从 HTTP 的输入可能是 Initiator,因此将该标识符复制到 InitiatorId 并为消息创建一个新的 CorrelationId,或者您可能只想对初始 CorrelationId 使用相同的标识符并让后续消息使用它作为发起者。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RabbitMq - ConversationId 与 CorrelationId - 哪个更适合跟踪特定请求? 的相关文章

随机推荐

  • 对不是 的直接子级的输入显示选项卡表单验证

    当未聚焦的选项卡出现验证错误时 选项卡标题应显示为红色 相反 当未聚焦的选项卡出现验证错误时 选项卡标题不会给出任何错误指示 当我使用子组件时会发生此问题 如果所有组件都是在创建 编辑级别定义的 则该选项卡将按预期变为红色 但如果存在嵌套组
  • dcast 重命名所有变量以数字开头

    所以我得到的数据如下所示 id year principal interest 1 011000600 2013 0 00 0 00 2 011000600 2014 544 03 0 00 3 011000700 2013 0 00 0
  • Java - 如果随后定义了 actionPerformed,JButton 文本就会消失

    这已经困扰我一段时间了 如果我定义setText在 JButton 上before定义setAction 文本消失 JButton test new JButton test setText test Before disappears t
  • 如何使用 Jasmine 监视匿名函数

    我正在使用 Jasmine 来测试我的角度应用程序 并希望监视匿名函数 使用角度通知服务https github com cgross angular notify https github com cgross angular notif
  • 将 SAS 数据集中的观测值读入数组

    这个问题与大型机上的 SAS 相关 尽管我相信在这种情况下没有什么区别 我有以下 SAS 数据集 Obs DATO T ALLOC T FRESP 1 19328 647 1804 2 19359 654 1797 3 19390 662
  • 如何自定义 Mini-Profiler UI

    我已经在我的 MVC 4 应用程序上安装了 Mini Profiler 它运行得非常顺利 我遇到的唯一问题是用户界面掩盖了用户界面的关键部分 我可以使用 css 在页面上移动它 但理想情况下我想让它默认为隐藏状态 并带有抽屉按钮以使其弹出
  • 自动生成我的 C++ 代码的 uml 图

    不久前 我担任 Java 编程入门课程的助教 我们使用了一个名为BlueJ http www bluej org 它有一个很好的功能 即开发文件的概述是一个轻量级的 UML 图 其中绘制了 使用 指针和继承指针 这使得可以轻松查看程序的结构
  • 查找包含任意数量的嵌套哈希和数组的哈希深处的键/值对

    Web 服务返回的哈希值包含未知数量的嵌套哈希值 其中一些包含数组 而数组又包含未知数量的嵌套哈希值 有些键不是唯一的 即存在于多个嵌套哈希中 然而 我真正关心的所有键都是唯一的 有什么办法可以给顶级哈希提供一个键 并取回它的值 即使键值对
  • 如何在 Web 应用程序中控制 iPhone 的屏幕方向

    我有一个非常基本的网页 它使用 flot 来创建canvas基于图 类似于 SO 用于声誉图的图 对于 PC 显示器 它应该正常输出 宽度 x 轴 为高度的 1 6 倍 但对于 iPhone 我希望页面默认为横向 而不是让它以 纵向 方向溢
  • 从 Snowflake 中的字符串中删除非 ASCII 字符

    如何从 Snowflake SQL 中的字符串中删除所有非 ASCII 字符 我遇到过使用 T SQL 等的解决方案 但没有关于如何在雪花中执行此操作的文章 正则表达式应该足够了 除非您考虑其他情况 select regexp replac
  • 存储凭据以供自动使用

    我已经环顾四周 由于我不是安全或加密专家 所以我仍然对如何在程序中实现加密感到困惑 我需要一台服务器来登录其 gitHub 帐户 以更新具有特殊标头的代码文件 我现在遇到的唯一难题是如何存储 检索服务器的凭据 PushOptions pus
  • 使用 Jackson 将消息从 JSON 反序列化为 POJO

    如果您在不检查消息的情况下不知道要使用什么类型的 POJO 那么如何使用 Jackson 将 JSON 文档反序列化为 POJO 有没有办法向 Jackson 注册一组 POJO 以便它可以根据消息选择一个 我试图解决的场景是通过线路接收
  • 如何在 Laravel 中将集合或自定义查询分页到 API json 中?

    我有一个复杂的查询 该查询不基于我想要对其输出进行分页的任何特定模型表 然而 Laravel 的内置分页依赖于模型和表格 如何对集合进行分页并使输出与 laravel 内置的分页输出格式匹配 我将其保存在 app Core Helpers
  • Rails 3:延迟加载与急切加载

    在 Rails 3 中 这些是相同还是不同 它们有何不同 o Appointment find 297 o service o Appointment includes service find 297 o service 我不确定 但看起
  • Scala Option 对象位于另一个 Option 对象内

    我有一个模型 其中有一些选项字段 其中包含另一个选项字段 例如 case class First second Option Second name Option String case class Second third Option
  • WiX,如何防止文件卸载,尽管我们忘记设置永久=“是”

    我们有一个用 Wix 创建的产品安装程序 其中包含一个程序包 V1 和一些配置文件 现在 我们将使用新的产品代码进行重大升级 其中旧版本的产品被卸载并且 V2 已安装 我们想要的是保存其中一个配置文件以防止卸载 因为 V2 也需要它 不幸的
  • R:深度复制函数参数

    考虑下面的代码 i 3 j i i 4 j i 然而 我想要的是 i 3 f lt function x j i x j i 4 f 4 16 but i want it to be 12 如果您想知道为什么我要这样做 您可以考虑这段代码
  • Java反射:如何从对象获取字段值,而不知道它的类

    比如说 我有一个返回自定义的方法List与一些物体 它们返回为Object大部头书 我需要从这些对象中获取某个字段的值 但我不知道这些对象的类 有没有办法通过反射或其他方式来做到这一点 假设一个简单的情况 你的领域是public List
  • 字形未加载

    由于某种原因 当我使用 twitter bootstrap 2 3 2 时 图像的图标未加载 我有默认结构 CSS 图像 js 其他一切都有效 我也尝试添加一个简单的图标 例如 span class icon icon ok OK span
  • RabbitMq - ConversationId 与 CorrelationId - 哪个更适合跟踪特定请求?

    RabbitMQ 似乎有两个非常相似的属性 我并不完全理解其中的区别 ConversationId and CorrelationId 我的用例如下 我有一个网站 可以生成Guid 该网站调用 API 将该唯一标识符添加到HttpReque