PageSourceSearch

https://www.rabbitmq.com/assets/js/a4df89e6.8a27aa1b.js

js rabbitmq.com collected 2026-09-24 06:04:53 UTC 27,833 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkrabbitmq_website=self.webpackChunkrabbitmq_website||[]).push([["11839"],{55279(e,t,n){n.r(t),n.d(t,{metadata:()=>a,default:()=>h,frontMatter:()=>i,contentTitle:()=>r,toc:()=>l,assets:()=>c});var a=JSON.parse('{"id":"stream-connections","title":"Stream Client Connections","description":"\x3c!--","source":"@site/docs/stream-connections.md","sourceDirName":".","slug":"/stream-connections","permalink":"/docs/next/stream-connections","draft":false,"unlisted":false,"editUrl":"https://github.com/rabbitmq/rabbitmq-website/tree/main/docs/stream-connections.md","tags":[],"version":"current","frontMatter":{"title":"Stream Client Connections","displayed_sidebar":"docsSidebar"},"sidebar":"docsSidebar","previous":{"title":"Stream Plugin","permalink":"/docs/next/stream"},"next":{"title":"Stream Core and Plugin","permalink":"/docs/next/stream-core-plugin-comparison"}}'),s=n(74848),o=n(28453);let i={title:"Stream Client Connections",displayed_sidebar:"docsSidebar"},r="Stream Client Connections",c={},l=[{value:"Overview",id:"overview",level:2},{value:"Stream Topology and What it Means for Publishers and Consumers",id:"topology",level:2},{value:"Consumers",id:"consumers",level:3},{value:"Best Practices for Publishers and Consumers",id:"best-practices",level:2},{value:"Stream Distribution Across Cluster Nodes",id:"stream-distribution",level:2},{value:"Stream Topology Discovery Using the <code>metadata</code> Command",id:"metadata-command",level:2},{value:"Limitations of the Metadata Command",id:"metadata-limitations",level:2},{value:"Tuning the Metadata Command: Advertised Host and Port",id:"advertised-host-port",level:2},{value:"Connecting to Nodes Behind a Load Balancer",id:"load-balancer",level:2},{value:"Client Workaround With a Load Balancer",id:"load-balancer-workaround",level:2},{value:"Using the Stream Java Client With a Load Balancer",id:"java-client-load-balancer",level:2},{value:"Best Practices, Summarized",id:"summary",level:2}];function d(e){let t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"stream-client-connections",children:"Stream Client Connections"})}),"\n",(0,s.jsx)(t.h2,{id:"overview",children:"Overview"}),"\n",(0,s.jsxs)(t.p,{children:["This companion guide to the ",(0,s.jsx)(t.a,{href:"./streams",children:"main guide on streams"})," covers how ",(0,s.jsx)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-server/blob/v4.2.x/deps/rabbitmq_stream/docs/PROTOCOL.adoc",children:"RabbitMQ Stream Protocol"})," clients can connect to a cluster to consume from and publish to streams."]}),"\n",(0,s.jsx)(t.p,{children:"The Stream Protocol has important differences from the other protocols supported\nby RabbitMQ, such as AMQP 1.0, AMQP 0-9-1, MQTT and STOMP."}),"\n",(0,s.jsxs)(t.admonition,{type:"important",children:[(0,s.jsx)(t.p,{children:"With streams, understanding the basics of the protocol and what client libraries can do is essential when cluster deployments involve extra layers\nlike containers and load balancers."}),(0,s.jsx)(t.p,{children:"Streams are optimized for maximum throughput, so the topic of data locality and client connections becomes significantly more important\nto cover in details."})]}),"\n",(0,s.jsx)(t.h2,{id:"topology",children:"Stream Topology and What it Means for Publishers and Consumers"}),"\n",(0,s.jsx)(t.admonition,{type:"tip",children:(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.a,{href:"./clustering#clustering-and-clients",children:"How messaging protocol clients connect to cluster nodes"})," is covered in the Clustering guide."]})}),"\n",(0,s.jsxs)(t.p,{children:["A stream is replicated and persistent, composed of a ",(0,s.jsx)(t.strong,{children:"leader"})," (primary member/replica) and ",(0,s.jsx)(t.strong,{children:"followers"})," (or secondary members/replicas).\nThese replicas are distributed across multiple nodes of a RabbitMQ cluster, as shown in the following diagram:"]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"A stream is a replicated and persistent data structure. It has a leader process which accepts write operations and replicas which can dispatch messages to applications.",src:n(42270).A+"",width:"1090",height:"206"})}),"\n",(0,s.jsxs)(t.p,{children:["Only the leader handles write operations, such as adding inbound messages to the stream. Any ",(0,s.jsx)(t.strong,{children:"member"})," of the stream \u2013 both the leader and any follower \u2014 can\nbe used for read operations, that is, delivering (dispat
1ching) messages to client applications."]}),"\n",(0,s.jsxs)(t.p,{children:["An application that publishes to a stream using the ",(0,s.jsx)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-server/blob/v4.2.x/deps/rabbitmq_stream/docs/PROTOCOL.adoc",children:"stream protocol"}),"\ncan connect to any node in the cluster: messages will automatically be routed\nfrom the node handling the client connection to the node that hosts the leader process."]}),"\n",(0,s.jsx)(t.p,{children:"However, in this case traffic routing will not be optimal if the connection and the stream leader are not on the same node.\nFor best data locality and efficiency, an application that publishes to a stream should connect to the node that hosts the leader of the stream,\nto avoid an extra network hop."}),"\n",(0,s.jsx)(t.h3,{id:"consumers",children:"Consumers"}),"\n",(0,s.jsxs)(t.p,{children:["The behavior differs for consuming applications. With the RabbitMQ Stream Protocol, messages are delivered (dispatched)\nto applications using the ",(0,s.jsx)(t.a,{href:"https://man7.org/linux/man-pages/man2/sendfile.2.html",children:(0,s.jsx)(t.code,{children:"sendfile"})})," system call: file chunks that contain messages are sent directly\nfrom the node file system to the network socket, without going through user space."]}),"\n",(0,s.jsxs)(t.p,{children:["This optimization is crucial to stream efficiency. However, it also requires that the node the consuming application is connected to hosts a member of the stream.\nWhether this member is the leader or a replica does not matter, as long as the data is on the file system, ready to be moved to the socket\nby the kernel executing a ",(0,s.jsx)(t.code,{children:"sendfile"})," system call."]}),"\n",(0,s.jsx)(t.p,{children:"This constraint for consuming applications is manageable in most cases. On the diagram above, each node has a member of the stream,\nso an application can connect to any node to consume. However, consider a 5-node cluster with streams using a replication factor of 2:\neach stream will have members only on 3 nodes out of the 5 nodes."}),"\n",(0,s.jsx)(t.p,{children:"In this case, consuming applications must select their connection node appropriately."}),"\n",(0,s.jsx)(t.h2,{id:"best-practices",children:"Best Practices for Publishers and Consumers"}),"\n",(0,s.jsx)(t.p,{children:"Publishing applications can connect to any node of a cluster and will always reach the leader process.\nConsuming applications must connect to a node that hosts a member of the target stream,\nwhere this member can be either the leader or a follower. The following best practices should be enforced whenever possible:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Publishing applications should always connect to the node that hosts the leader process of the target stream"}),"\n",(0,s.jsx)(t.li,{children:"Consuming applications should always connect to a node that hosts a replica of the target stream"}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The following diagram illustrates these best practices:"}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"Client applications that publish to a stream should connect to the node that hosts the stream leader, clients applications that consume from a stream should connect to a node that hosts a replica of this stream.",src:n(10579).A+"",width:"1105",height:"434"})}),"\n",(0,s.jsx)(t.p,{children:"Connecting directly to the node of the stream leader avoids a network hop, as published messages ultimately must go to the leader.\nUsing a replica for consuming relieves the leader from some load, allowing it to spend more resources handling all the write operations."}),"\n",(0,s.jsxs)(t.p,{children:["These best practices are integrated into the official RabbitMQ Stream Protocol ",(0,s.jsx)(t.a,{href:"/client-libraries/devtools",children:"client libraries"}),",\nkeeping these details from complicating application code."]}),"\n",(0,s.jsx)(t.admonition,{type:"tip",children:(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Publishing applications should always connect to the node that hosts the leader process of the target stream"}),"\n",(0,s.jsx)(t.li,{children:"Consuming applications should always connect to a node that hosts a replica of the target stream"}),"\n"]})}),"\n",(0,s.jsx)(t.p,{children:"The stream protocol allows client libraries (and applications) to discover the topology of a given stream through the metadata command."}),"\n",(0,s.jsx)(t.h2,{id:"stream-distribution",children:"Stream Distribution Across Cluster Nodes"}),"\n",(0,s.jsxs)(t.p,{children:["Before examining the ",(0,s.jsx)(t.code,{children:"metadata"})," command of the stream protocol, it is important to understand how streams distribute across the nodes of a RabbitMQ cluster.\nA stream has a leader Erlang process located on one node and replica Erlang processes located on other nodes.\nWith multiple streams, the leader and follower processes are spread across the cluster nodes."]}),"\n",(0,s.jsx)(t.p,{children:"With the exception of single node cluster
1s, no single RabbitMQ node should host all the stream leaders."}),"\n",(0,s.jsx)(t.p,{children:"A set of stream members (replicas) can be thought of as a small cluster within the RabbitMQ cluster,\nas illustrated with several streams in the following diagram:"}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"Stream leaders spread across the nodes of a cluster. This means that a given node does not have to contain all the leaders at some point.",src:n(12420).A+"",width:"1076",height:"279"})}),"\n",(0,s.jsxs)(t.p,{children:["The distribution of leaders across the cluster depends on the ",(0,s.jsx)(t.a,{href:"./streams#leader-election",children:"leader locator strategy"}),"\nin effect at stream declaration time."]}),"\n",(0,s.jsxs)(t.h2,{id:"metadata-command",children:["Stream Topology Discovery Using the ",(0,s.jsx)(t.code,{children:"metadata"})," Command"]}),"\n",(0,s.jsxs)(t.p,{children:["The stream protocol provides a ",(0,s.jsxs)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-server/blob/v4.2.x/deps/rabbitmq_stream/docs/PROTOCOL.adoc#metadata",children:[(0,s.jsx)(t.code,{children:"metadata"})," command"]})," that\nallows clients to query the topology of one or several streams. For each queried stream, the response contains\nthe hostname and port of the nodes that host the leader and replicas."]}),"\n",(0,s.jsx)(t.p,{children:"The following diagram illustrates how a client application already connected to one of the nodes can discover the topology of a given stream:"}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"A client can find out about the topology of a stream by using the metadata command.",src:n(51751).A+"",width:"1105",height:"434"})}),"\n",(0,s.jsxs)(t.p,{children:["A common pattern is to provide one or several node endpoints to a client library, then using the ",(0,s.jsx)(t.code,{children:"metadata"})," command once connected\nto discover the topology of the target stream, and then connecting to the appropriate nodes depending on the operations (publishing or consuming)."]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"Once a client application knows about the topology of a stream, it can connect to the appropriate nodes to work with it: the node that hosts the stream leader to publish and nodes that host the stream replicas to consume.",src:n(63059).A+"",width:"1105",height:"434"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"metadata"})," command is essential for client libraries to enforce the best practices mentioned above."]}),"\n",(0,s.jsx)(t.p,{children:"Unfortunately, the metadata returned with all defaults will not always be accurate, or at least not accurate enough for the client application to connect successfully."}),"\n",(0,s.jsx)(t.h2,{id:"metadata-limitations",children:"Limitations of the Metadata Command"}),"\n",(0,s.jsxs)(t.p,{children:["RabbitMQ streams will return the hostname of each node for the host metadata (more specifically, the host part of the node name, the ",(0,s.jsx)(t.code,{children:"{hostname}"})," part in ",(0,s.jsx)(t.code,{children:"rabbit@{hostname}"}),").\nThis works as long as the client can resolve the hostname of the target node."]}),"\n",(0,s.jsx)(t.p,{children:"However, when RabbitMQ nodes are deployed in containerized environments, the hostname can be ambiguous and may not resolve on the hosts where applications\nare deployed."}),"\n",(0,s.jsx)(t.p,{children:"The following diagram illustrates a 3-node RabbitMQ cluster where the nodes are containers running on different VMs.\nA client application can connect to the nodes if the ports are mapped correctly, but cannot do so using the hostname of the containers."}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"Using the hostname in metadata will not work when the nodes run in containers, as it is very unlikely the client and the nodes can see each other directly.",src:n(18313).A+"",width:"1156",height:"535"})}),"\n",(0,s.jsxs)(t.p,{children:['The RabbitMQ node with the stream plugin enabled does its best but it cannot know what hostnames clients can or cannot resolve, and why.\nFortunately, it is possible to configure what a node returns when asked for its "coordinates" for the ',(0,s.jsx)(t.code,{children:"metadata"})," command."]}),"\n",(0,s.jsx)(t.h2,{id:"advertised-host-port",children:"Tuning the Metadata Command: Advert
1ised Host and Port"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsxs)(t.a,{href:"./stream#advertised-host-port",children:[(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," configuration entries"]})," of the stream plugin should be used to specify\nwhat a node returns when asked how to be contacted. The plugin will return these values as given, without any validation.\nThe DNS setup must allow client applications to connect to the node using these configured values. In practice this means\nthat the overridden advertised hostnames must be stable and resolvable by application hosts."]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"It is possible to configure advertised host and port if the default values are not appropriate.",src:n(80326).A+"",width:"1108",height:"569"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," settings should resolve connection issues where client applications cannot connect to nodes due to\nusing the hostnames advertised by default. These settings are important to consider when deploying a RabbitMQ cluster with containerized nodes and streams."]}),"\n",(0,s.jsx)(t.admonition,{type:"important",children:(0,s.jsxs)(t.p,{children:["When RabbitMQ nodes use hostnames that applications cannot resolve, using the ",(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," settings\nbecomes essential."]})}),"\n",(0,s.jsx)(t.p,{children:"There remains one common use case where this discovery mechanism can be problematic: when a load balancer sits between client applications and the cluster nodes."}),"\n",(0,s.jsx)(t.h2,{id:"load-balancer",children:"Connecting to Nodes Behind a Load Balancer"}),"\n",(0,s.jsx)(t.p,{children:"Having a load balancer in front of a RabbitMQ cluster is a common scenario. A load balancer can make the data locality problem outlined above much worse.\nFortunately, solutions exist."}),"\n",(0,s.jsxs)(t.p,{children:["When using the metadata command with a load balancer, issues arise: the client will receive the nodes information and use it to connect ",(0,s.jsx)(t.strong,{children:"directly"})," to the nodes,\nbypassing the load balancer. The following diagram illustrates this situation:"]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"Metadata hints are less useful when a load balancer sits between the client and the nodes. The client application will skip the load balancer and try to connect directly to the nodes. This can be impossible or a security concern.",src:n(8375).A+"",width:"1089",height:"531"})}),"\n",(0,s.jsx)(t.p,{children:"This behavior is usually undesirable."}),"\n",(0,s.jsxs)(t.admonition,{type:"warning",children:[(0,s.jsxs)(t.p,{children:["Setting the ",(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," configuration entries to use the load balancer information so client applications always\nconnect to the load balancer is not recommended."]}),(0,s.jsx)(t.p,{children:"This approach prevents enforcing the best practices (publishing to the leader, consuming from replica) and in deployments where streams are not on all nodes,\nconsuming will fail if the application connects to a node without a stream member."})]}),"\n",(0,s.jsx)(t.p,{children:"Client libraries can implement a workaround to resolve this problem."}),"\n",(0,s.jsx)(t.h2,{id:"load-balancer-workaround",children:"Client Workaround With a Load Balancer"}),"\n",(0,s.jsx)(t.p,{children:"A client application can always connect to the load balancer and end up connected to the appropriate node using the following approach:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["Use the ",(0,s.jsx)(t.code,{children:"metadata"})," command but ",(0,s.jsx)(t.strong,{children:"intentionally ignore"})," the discovered result and always connect to the load balancer"]}),"\n",(0,s.jsx)(t.li,{children:"Retry connecting until connected to an appropriate node"}),"\n"]}),"\n",(0,s.jsxs)(t.p,{children:['The "coordinates" of the node (hostname and port, or ',(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," if configured) are available in a stream protocol connection.\nA client application can determine to which node it is connected."]}),"\n",(0,s.jsxs)(t.p,{children:["This means that ",(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"}),' should not be configured when a load balancer is in use.\nThe "coordinates" of a node that the ',(0,s.jsx)(t.code,{children:"metadata"})," command returns are not used to connect in this case, as the client always connects to the load balancer.\nThey are used to ",(0,s.jsx)(t.strong,{children:"correlate"})," the connection the load balancer provides with the node the client expects, and the hostname is sufficient for this purpose."]}),"\n",(0,s.jsx)(t.admonition,{type:"tip",children:(0,s.jsx)(t.p,{children:(0,s.jsxs)(t.strong,{children:["This means ",(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," should not be configured when a load balancer is in use."]})})}),"\n",(0,s.jsx)(t.p,{children:"Consider the following scenario:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["A publishing application knows the leader of its targeted stream is on ",(0,s.jsx)(t.code,{children:"node-1"})," thanks to the response of a ",(0,s.jsx)(t.code,{children:"metadata"})," request"]}),"\n",(0,s.jsx)(t.li,{children:"It creates a new connection using the load balancer address"}),"\n",(0,s.jsxs)(t.li,{children:["The load balancer chooses to connect to ",(0,s.jsx)(t.code,{children:"node-3"})]}),"\n",(0,s.jsxs)(t.li,{children:["The connection is properly established but the client application discovers it is connected to ",(0,s.jsx)(t.code,{children:"node-3"}),", it immediately closes the connection, and retries"]}),"\n",(0,s.jsxs)(t.li,{children:["The load balancer chooses ",(0,s.jsx)(t.code,{children:"node-1"})," on the next attempt"]}),"\n",(0,s.jsx)(t.li,{children:"The application is connected to the correct node and proceeds with publishing using this connection"}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"The following diagram illustrates this process:"}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.img,{alt:"A client can choose to ignore the metadata hints and always use the load balancer. As stream connections convey the node hostname they originate from, the client can know whether it is connected to the right node or not, and keep the connection or close it and retry.",src:n(8392).A+"",width:"1102",height:"598"})}),"\n",(0,s.jsxs)(t.p,{children:["As stream connections are meant to be long-lived and stream applications do not typically have significant connection churn,\nretrying to connect will not lead to a ",(0,s.jsx)(t.a,{href:"./connections#high-connection-churn",children:"high connection churn"})," scenario and is not a concern."]}),"\n",(0,s.jsx)(t.p,{children:"This solution assumes that the load balancer will not always connect to the same backend server.\nRound robin is an appropriate balancing strategy for this case."}),"\n",(0,s.jsxs)(t.p,{children:["Setting ",(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," is not necessary when using this technique and setting them to the load balancer coordinates for all nodes can be\nimpossible or difficult to achieve. Allowing each node to return its hostname is appropriate here, as the hostname should be unique in a network."]}),"\n",(0,s.jsx)(t.p,{children:"This responsibility lies with the client library. The following section describes how this is implemented with the stream Java client."}),"\n",(0,s.jsx)(t.h2,{id:"java-client-load-balancer",children:"Using the Stream Java Client With a Loa
1d Balancer"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-stream-java-client",children:"stream Java client"})," provides ",(0,s.jsxs)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-stream-java-client/blob/main/src/main/java/com/rabbitmq/stream/AddressResolver.java",children:["an ",(0,s.jsx)(t.code,{children:"AddressResolver"})," extension point"]}),". It is used whenever a new connection is created: from the passed-in ",(0,s.jsx)(t.code,{children:"Address"})," (the node to connect to based on the ",(0,s.jsx)(t.code,{children:"metadata"})," query), the address resolver can provide logic to compute the actual address to use. The default implementation returns the given address. To implement the workaround presented above when a load balancer is in use, always return the address of the load balancer, as shown in the following code snippet:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-java",children:'Address entryPoint = new Address("my-load-balancer", 5552);\nEnvironment environment = Environment.builder()\n    .host(entryPoint.host())\n    .port(entryPoint.port())\n    .addressResolver(address -> entryPoint)\n    .build();\n'})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"https://rabbitmq.github.io/rabbitmq-stream-java-client/stable/htmlsingle/#the-performance-tool",children:"stream PerfTest tool"})," also supports this mode when the ",(0,s.jsx)(t.code,{children:"--load-balancer"})," option is enabled. The following commands configure the tool to always use the same entry point for publishers and consumers connections:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-shell",children:"# with the Java binary\njava -jar stream-perf-test.jar --uris rabbitmq-stream://my-load-balancer:5552 --load-balancer\n\n# with Docker\ndocker run -it --rm pivotalrabbitmq/stream-perf-test --uris rabbitmq-stream://my-load-balancer:5552 --load-balancer\n"})}),"\n",(0,s.jsx)(t.h2,{id:"summary",children:"Best Practices, Summarized"}),"\n",(0,s.jsx)(t.p,{children:"Client applications connecting using the stream protocol should follow these guidelines:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:"Publishing applications should connect to the node that hosts the leader of the target stream"}),"\n",(0,s.jsx)(t.li,{children:"Consuming applications should connect to a node that hosts a replica of the target stream"}),"\n",(0,s.jsxs)(t.li,{children:["Client applications must use the ",(0,s.jsxs)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-server/blob/v4.2.x/deps/rabbitmq_stream/docs/PROTOCOL.adoc#metadata",children:[(0,s.jsx)(t.code,{children:"metadata"})," stream protocol command"]})," to learn about the topology of the streams they want to interact with"]}),"\n",(0,s.jsxs)(t.li,{children:["The stream ",(0,s.jsx)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-stream-java-client",children:"Java"})," and ",(0,s.jsx)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-stream-go-client",children:"Go"})," clients enforce these best practices"]}),"\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"metadata"})," command returns by default the node's hostname and listener port, which can be problematic in containerized environments"]}),"\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsxs)(t.a,{href:"./stream#advertised-host-port",children:[(0,s.jsx)(t.code,{children:"advertised_host"})," and ",(0,s.jsx)(t.code,{children:"advertised_port"})," configuration entries"]})," allow specifying what values a node should return for the ",(0,s.jsx)(t.code,{children:"metadata"})," command"]}),"\n",(0,s.jsx)(t.li,{children:"A load balancer can confuse a client library that will try to bypass it to connect directly to the nodes"}),"\n",(0,s.jsx)(t.li,{children:"Client libraries can provide a workaround to work properly with a load balancer"}),"\n",(0,s.jsxs)(t.li,{children:["The stream ",(0,s.jsx)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-stream-java-client",children:"Java"})," and ",(0,s.jsx)(t.a,{href:"https://github.com/rabbitmq/rabbitmq-stream-go-client",children:"Go"})," clients implement such a workaround"]}),"\n"]})]})}function h(e={}){let{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8392(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/load-balancer-ignore-metadata-9c9147b8395a556ba8c7859e6b8d407e.svg"},8375(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/load-balancer-18cf63114d0716feefd56d3f2fba497a.svg"},51751(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/metadata-command-0e46d66450897d6cdbcf45997f2bd124.svg"}
1,80326(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/metadata-hints-b023812c1bf1ecdd8ac8e37b634b02a5.svg"},12420(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/stream-spread-cd9eff9b53ca90a91b1ee67adc6cb3b3.svg"},42270(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/stream-topology-4c19caa1a3dc590aeb99e653fb2221e6.svg"},18313(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/use-connection-hints-with-docker-c4d7411314f6ffe6d10e7d57afe33486.svg"},63059(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/use-connection-hints-e4243348430033e5244ae5db8475ea3c.svg"},10579(e,t,n){n.d(t,{A:()=>a});let a=n.p+"assets/images/well-behaved-clients-2cb798de6212bd9ba9a37810ad929a77.svg"},28453(e,t,n){n.d(t,{R:()=>i,x:()=>r});var a=n(96540);let s={},o=a.createContext(s);function i(e){let t=a.useContext(o);return a.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),a.createElement(o.Provider,{value:t},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.