我们计划部署一个ActiveMQ服务器场,该服务器场支持跨多个服务器的400多万个并发连接。我们没有使用基于我们设计的聚类。客户端使用MQTT进行连接,并从自己的主题进行订阅/使用,并发布到共享的虚拟主题。我们考虑的是每台服务器100k连接和20k msg / s。我无法达到这个数额。我成功地连接了这个数量,但是它的吞吐量让我受伤。
为了测试,我使用的是基于FuseSource MQTT客户端的Async(回调而非未来)版本的多线程客户端。使用该客户端,我能够在系统上加载足够的负载,以便我看到队列积压。我正在使用“java -jar activemq-all-5.13.0.jar dstat”获取队列积压。
我在很多方面调整了服务器,但无法利用所有资源。 Iostat显示低%util,top显示可用的cpu资源。
我的服务器在AWS m3.2xlarge(8vCPU,30G ram)上运行。
我正在使用“java -Xms12G -Xmx20G -jar ...”启动activemq
以下是我启动经纪人的方式。请注意,我已经更改了许多设置,但它们似乎并不重要。
@Bean
public BrokerService getBrokerService() throws Exception {
String hostname= InetAddress.getLocalHost().getHostName();
// Create broker
BrokerService broker = new BrokerService();
broker.setBrokerName("ActiveMQ"+hostname);
broker.setUseShutdownHook(true);
broker.setAdvisorySupport( false );
broker.setUseJmx(true);
broker.setDeleteAllMessagesOnStartup( true );
broker.setPopulateJMSXUserID( true );
broker.setPopulateUserNameInMBeans( true );
broker.setUseAuthenticatedPrincipalForJMSXUserID( true );
broker.setUseVirtualTopics( true );
// I have altered these but they don't seem to change anything.
broker.setDedicatedTaskRunner( true );
broker.setEnableStatistics( true );
broker.setStartAsync( true );
// Enable JMX bean
final ManagementContext managementContext = new ManagementContext();
managementContext.setCreateConnector(true);
broker.setManagementContext( managementContext );
// Enable LevelDB
broker.setPersistent( true );
File dataFileDir = new File("/activemq/data/leveldb);
LevelDBStore adapter = new LevelDBStore();
adapter.setDirectory(dataFileDir);
broker.setPersistenceAdapter(adapter);
// Turn flow control off
PolicyEntry policy = new PolicyEntry();
policy.setOptimizedDispatch( true );
policy.setProducerFlowControl( false );
policy.setGcInactiveDestinations( true );
DispatchPolicy dp = new RoundRobinDispatchPolicy();
policy.setDispatchPolicy( dp );
PolicyMap policyMap = new PolicyMap();
policyMap.setDefaultEntry( policy );
broker.setDestinationPolicy( policyMap );
// Set system usage
SystemUsage memoryManager = new SystemUsage();
MemoryUsage memoryUsage = new MemoryUsage();
memoryUsage.setPercentOfJvmHeap( 75 );
memoryManager.setMemoryUsage( memoryUsage );
StoreUsage storeUsage = new StoreUsage();
storeUsage.setLimit( 100*ONE_GB );
memoryManager.setStoreUsage( storeUsage );
TempUsage tempDiskUsage = new TempUsage();
tempDiskUsage.setLimit( 100*ONE_GB );
memoryManager.setTempUsage( tempDiskUsage );
broker.setSystemUsage( memoryManager );
// Add transports
TransportConnector openwireconnector = new TransportConnector();
openwireconnector.setName( "openwire" );
openwireconnector.setUri(new URI("tcp://0.0.0.0:61616"));
broker.addConnector(openwireconnector);
TransportConnector mqttnioconnector = new TransportConnector();
mqttnioconnector.setName( "mqtt+nio" );
mqttnioconnector.setUri(new URI("mqtt+nio://0.0.0.0:1883"));
broker.addConnector(mqttnioconnector);
TransportConnector wsconnector = new TransportConnector();
wsconnector.setName( "ws" );
wsconnector.setUri(new URI("ws://0.0.0.0:61614"));
broker.addConnector(wsconnector);
// Start
broker.start();
broker.waitUntilStarted();
return broker;
}
}
我在连接到ActiveMQ的另一台服务器上使用spring JMS侦听器。
@Component
public class MqttMessageListener {
@JmsListener(destination = "Consumer.A.VirtualTopic.Message")
public void processMessage(BytesMessage bytesMessage) {
// I consume and discard here just for testing. No work is being done to isolate issue.
}
}
@Configuration
@EnableJms
public class AppConfig {
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setConcurrency(“3-10”); // I have tried many variation including 300-1000 although it seems to top out at 500.
factory.setAutoStartup( true );
return factory;
}
}
使用上面的MqttMessageListener.processMessage方法,我只能消耗大约15k msgs / sec。由于30%以上的CPU空闲和低磁盘/网络利用率,我不确定为什么我不能做得更好。
问题: