이 콘텐츠는 선택한 언어로 제공되지 않습니다.
Chapter 8. Configuring the Messaging Transports
This section describes the concepts critical to understanding JBoss EAP messaging transports, specifically connectors and acceptors. Acceptors are used on the server to define how it can accept connections, while connectors are used by the client to define how it connects to a server. Each concept is discussed in turn and then a practical example shows how clients can make connections to a JBoss EAP messaging server, using JNDI or the Core API.
8.1. Acceptor and Connector Types
There are three main types of acceptor and connector defined in the configuration of JBoss EAP.
in-vm
: In-vm is short for Intra Virtual Machine. Use this connector type when both the client and the server are running in the same JVM eg., Message Driven Beans (MDBs) running in the same instance of JBoss EAP.
http
: Used when client and server are running in different JVMs. Uses the undertow
subsystem’s default port of 8080
and is thus able to multiplex messaging communications over HTTP. Red Hat recommends using the http
connector when the client and server are running in different JVMs due to considerations such as port management, especially in a cloud environment.
remote
: Remote transports are Netty-based components used for native TCP communication when the client and server are running in different JVMs. An alternative to http
when it cannot be used.
A client must use a connector that is compatible with one of the server’s acceptors. For example, only an in-vm-connector
can connect to an in-vm-acceptor
, and only a http-connector
can connect to an http-acceptor
, and so on.
You can have the management CLI list the attributes for a given acceptor or connector type using the read-children-attributes
operation. For example, to see the attributes of all the http-connectors
for the default messaging server you would enter:
/subsystem=messaging-activemq/server=default:read-children-resources(child-type=http-connector,include-runtime=true)
The attributes of all the http-acceptors
are read using a similar command:
/subsystem=messaging-activemq/server=default:read-children-resources(child-type=http-acceptor,include-runtime=true)
The other acceptor and connector types follow the same syntax. Just provide child-type
with the acceptor or connector type, for example, remote-connector
or in-vm-acceptor
.
8.2. Acceptors
An acceptor defines which types of connection are accepted by the JBoss EAP integrated messaging server. You can define any number of acceptors per server. The sample configuration below is modified from the default full-ha
configuration profile and provides an example of each acceptor type.
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0"> <server name="default"> ... <http-acceptor name="http-acceptor" http-listener="default"/> <remote-acceptor name="legacy-messaging-acceptor" socket-binding="legacy-messaging"/> <in-vm-acceptor name="in-vm" server-id="0"/> ... </server> </subsystem>
In the above configuration, the http-acceptor
is using Undertow’s default http-listener
which listens on JBoss EAP’s default http port, 8080. The http-listener
is defined in the undertow
subsystem:
<subsystem xmlns="urn:jboss:domain:undertow:3.0"> ... <server name="default-server"> <http-listener name="default" redirect-socket="https" socket-binding="http"/> ... </server> ... </subsystem>
Also note how the remote-acceptor
above uses the socket-binding
named legacy-messaging
, which is defined later in the configuration as part of the server’s default socking-binding-group
.
<server xmlns="urn:jboss:domain:4.1"> ... <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}"> ... <socket-binding name="legacy-messaging" port="5445"/> ... </socket-binding-group> </server>
In this example, the legacy-messaging
socket-binding
binds JBoss EAP to port 5445
, and the remote-acceptor
above claims the port on behalf of the messaging-activemq
subsystem for use by legacy clients.
Lastly, the in-vm-acceptor
uses a unique value for the server-id
attribute so that this server instance can be distinguished from other servers that might be running in the same JVM.
8.3. Connectors
A connector defines how to connect to an integrated JBoss EAP messaging server, and is used by a client to make connections.
You might wonder why connectors are defined on the server when they are actually used by the client. The reasons for this include:
- In some instances, the server might act as a client when it connects to another server. For example, one server might act as a bridge to another, or it might want to participate in a cluster. In such cases, the server needs to know how to connect to other servers, and that is defined by connectors.
-
A server can provide connectors using a
ConnectionFactory
which is looked up by clients using JNDI, so creating connection to the server is simpler.
You can define any number of connectors per server. The sample configuration below is based on the full-ha
configuration profile and includes connectors of each type.
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0"> <server name="default"> ... <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http"/> <remote-connector name="legacy-remoting-connector" socket-binding="legacy-remoting"/> <in-vm-connector name="in-vm" server-id="0"/> ... </server> </subsystem>
Like the http-acceptor
from the full-ha
profile, the http-connector
uses the default http-listener
defined by the undertow
subsystem. The endpoint
attribute declares which http-acceptor
to connect to. In this case, the connector will connect to the default http-acceptor
.
Also, note that the remote-connector
references the same socket-binding
as its remote-acceptor
counterpart. Lastly, the in-vm-connector
uses the same value for server-id
as the in-vm-acceptor
since they both run inside the same server instance.
8.4. Configuring Acceptors and Connectors
There are a number of configuration options for connectors and acceptors. They appear in the configuration as child <param>
elements. Each <param>
element includes a name
and value
attribute pair that is understood and used by the default Netty-based factory class responsible for instantiating a connector or acceptor.
In the management CLI, each remote connector or acceptor element includes an internal map of the parameter name and value pairs. For example, to add a new param
to a remote-connector
named myRemote
use the following command:
/subsystem=messaging-activemq/server=default/remote-connector=myRemote:map-put(name=params,key=foo,value=bar)
Retrieve parameter values using a similar syntax.
/subsystem=messaging-activemq/server=default/remote-connector=myRemote:map-get(name=params,key=foo) { "outcome" => "success", "result" => "bar" }
You can also include parameters when you create an acceptor or connector, as in the example below.
/subsystem=messaging-activemq/server=default/remote-connector=myRemote:add(socket-binding=mysocket,params={foo=bar,foo2=bar2})
Property | Description |
---|---|
batch-delay |
Before writing packets to the transport, the messaging server can be configured to batch up writes for a maximum of |
direct-deliver |
When a message arrives on the server and is delivered to waiting consumers, by default, the delivery is done on the same thread on which the message arrived. This gives good latency in environments with relatively small messages and a small number of consumers but reduces the throughput and latency. For highest throughput you can set this property as |
http-upgrade-enabled |
Used by an |
http-upgrade-endpoint |
Specifies the |
local-address | For a http or a remote connector, this is used to specify the local address which the client will use when connecting to the remote address. If a local address is not specified then the connector will use any available local address. |
local-port |
For a http or a remote connector, this is used to specify which local port the client will use when connecting to the remote address. If the local-port default is used (0) then the connector will let the system pick up an ephemeral port. Valid port values are |
nio-remoting-threads |
If configured to use NIO, the messaging will by default use a number of threads equal to three times the number of cores (or hyper-threads) as reported by |
tcp-no-delay |
If this is |
tcp-send-buffer-size |
This parameter determines the size of the TCP send buffer in bytes. The default is |
tcp-receive-buffer-size |
This parameter determines the size of the TCP receive buffer in bytes. The default is |
use-nio-global-worker-pool |
This parameter will ensure all JMS connections share a single pool of Java threads, rather than each connection having its own pool. This serves to avoid exhausting the maximum number of processes on the operating system. The default is |
8.5. Connecting to a Server
If you want to connect a client to a server, you have to have a proper connector. There are two ways to do that. You could use a ConnectionFactory which is configured on the server and can be obtained via JNDI lookup. Alternatively, you could use the ActiveMQ Artemis core API and configure the whole ConnectionFactory
on the client side.
8.5.1. JMS Connection Factories
Clients can use JNDI to look up ConnectionFactory objects which provide connections to the server. Connection Factories can expose each of the three types of connector:
A connection-factory
referencing a remote-connector
can be used by a remote client to send messages to or receive messages from the server (assuming the connection-factory has an appropriately exported entry). A remote-connector
is associated with a socket-binding
that tells the client using the connection-factory
where to connect.
A connection-factory
referencing an in-vm-connector
is suitable to be used by a local client to either send messages to or receive messages from a local server. An in-vm-connector
is associated with a server-id
which tells the client using the connection-factory
where to connect, since multiple messaging servers can run in a single JVM.
A connection-factory
referencing a http-connector
is suitable to be used by a remote client to send messages to or receive messages from the server by connecting to its HTTP port before upgrading to the messaging protocol. A http-connector
is associated with the socket-binding
that represents the HTTP socket, which by default is named http
.
Since JMS 2.0, a default JMS connection factory is accessible to EE application under the JNDI name java:comp/DefaultJMSConnectionFactory
. The messaging-activemq
subsystem defines a pooled-connection-factory
that is used to provide this default connection factory.
Below are the default connectors and connection factories that are included in the full
configuration profile for JBoss EAP:
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0"> <server name="default"> [...] <http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor" /> <http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput"> <param name="batch-delay" value="50"/> </http-connector> <in-vm-connector name="in-vm" server-id="0"/> [...] <connection-factory name="InVmConnectionFactory" connectors="in-vm" entries="java:/ConnectionFactory" /> <pooled-connection-factory name="activemq-ra" transaction="xa" connectors="in-vm" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory"/> [...] </server> </subsystem>
The entries
attribute of a factory specifies the JNDI names under which the factory will be exposed. Only JNDI names bound in the java:jboss/exported
namespace are available to remote clients. If a connection-factory
has an entry bound in the java:jboss/exported
namespace a remote client would look-up the connection-factory
using the text after java:jboss/exported
. For example, the RemoteConnectionFactory
is bound by default to java:jboss/exported/jms/RemoteConnectionFactory
which means a remote client would look-up this connection-factory using jms/RemoteConnectionFactory
. A pooled-connection-factory
should not have any entry bound in the java:jboss/exported
namespace because a pooled-connection-factory
is not suitable for remote clients.
8.5.2. Connecting to the Server Using JNDI
If the client resides within the same JVM as the server, it can use the in-vm
connector provided by the InVmConnectionFactory
. Here is how the InvmConnectionFactory
is typically configured, as found for example in standalone-full.xml
.
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm" />
Note the value of the entries
attribute. Clients using the InVmConnectionFactory should drop the leading java:/
during lookup, as in the following example:
InitialContext ctx = new InitialContext(); ConnectionFactory cf = (ConnectionFactory)ctx.lookup("ConnectionFactory"); Connection connection = cf.createConnection();
Remote clients use the RemoteConnectionFactory
, which is usually configured as below:
<connection-factory name="RemoteConnectionFactory" scheduled-thread-pool-max-size="10" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
Remote clients should ignore the leading java:jboss/exported/
of the value for entries
, following the example of the code snippet below:
final Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory"); env.put(Context.PROVIDER_URL, "http-remoting://remotehost:8080"); InitialContext remotingCtx = new InitialContext(env); ConnectionFactory cf = (ConnectionFactory) remotingCtx.lookup("jms/RemoteConnectionFactory");
Note the value for the PROVIDER_URL
property and how the client is using the JBoss EAP http-remoting protocol. Note also how the client is using the org.jboss.naming.remote.client.InitialContextFactory
, which implies the client has this class and its encompassing client jar somewhere in the classpath. For maven projects, this can be achieved by including the following dependency:
<dependencies> <dependency> <groupId>org.wildfly</groupId> <artifactId>wildfly-jms-client-bom</artifactId> <type>pom</type> </dependency> </dependencies>
8.5.3. Connecting to the Server Using the Core API
You can use the Core API to make client connections without needing a JNDI lookup. Clients using the Core API require a client jar in their classpath, just as JNDI-based clients.
ServerLocator
Clients use ServerLocator
instances to create ClientSessionFactory
instances. As their name implies, ServerLocator
instances are used to locate servers and create connections to them.
In JMS terms think of a ServerLocator
in the same way you would a JMS Connection Factory.
ServerLocator
instances are created using the ActiveMQClient
factory class.
ServerLocator locator = ActiveMQClient.createServerLocatorWithoutHA(new TransportConfiguration(InVMConnectorFactory.class.getName()));
ClientSessionFactory
Clients use a ClientSessionFactory
to create ClientSession
instances, which are basically connections to a server. In JMS terms think of them as JMS connections.
ClientSessionFactory
instances are created using the ServerLocator
class.
ClientSessionFactory factory = locator.createClientSessionFactory();
ClientSession
A client uses a ClientSession
for consuming and producing messages and for grouping them in transactions. ClientSession
instances can support both transactional and non transactional semantics and also provide an XAResource interface so messaging operations can be performed as part of a JTA transaction.
ClientSession
instances group ClientConsumers
and ClientProducers
.
ClientSession session = factory.createSession();
The simple example below highlights some of what was just discussed:
ServerLocator locator = ActiveMQClient.createServerLocatorWithoutHA( new TransportConfiguration( InVMConnectorFactory.class.getName())); // In this simple example, we just use one session for both // producing and consuming ClientSessionFactory factory = locator.createClientSessionFactory(); ClientSession session = factory.createSession(); // A producer is associated with an address ... ClientProducer producer = session.createProducer("example"); ClientMessage message = session.createMessage(true); message.getBodyBuffer().writeString("Hello"); // We need a queue attached to the address ... session.createQueue("example", "example", true); // And a consumer attached to the queue ... ClientConsumer consumer = session.createConsumer("example"); // Once we have a queue, we can send the message ... producer.send(message); // We need to start the session before we can -receive- messages ... session.start(); ClientMessage msgReceived = consumer.receive(); System.out.println("message = " + msgReceived.getBodyBuffer().readString()); session.close();