use of org.apache.pulsar.broker.loadbalance.LoadManager in project incubator-pulsar by apache.
the class BrokerServiceLookupTest method testModularLoadManagerSplitBundle.
/**
* <pre>
* When broker-1's Modular-load-manager splits the bundle and update local-policies, broker-2 should get watch of
* local-policies and update bundleCache so, new lookup can be redirected properly.
*
* (1) Start broker-1 and broker-2
* (2) Make sure broker-2 always assign bundle to broker1
* (3) Broker-2 receives topic-1 request, creates local-policies and sets the watch
* (4) Broker-1 will own topic-1
* (5) Broker-2 will be a leader and trigger Split the bundle for topic-1
* (6) Broker-2 should get the watch and update bundle cache
* (7) Make lookup request again to Broker-2 which should succeed.
*
* </pre>
*
* @throws Exception
*/
@Test(timeOut = 5000)
public void testModularLoadManagerSplitBundle() throws Exception {
log.info("-- Starting {} test --", methodName);
final String loadBalancerName = conf.getLoadManagerClassName();
try {
final String namespace = "my-property/use/my-ns";
// (1) Start broker-1
ServiceConfiguration conf2 = new ServiceConfiguration();
conf2.setAdvertisedAddress("localhost");
conf2.setBrokerServicePort(PortManager.nextFreePort());
conf2.setBrokerServicePortTls(PortManager.nextFreePort());
conf2.setWebServicePort(PortManager.nextFreePort());
conf2.setWebServicePortTls(PortManager.nextFreePort());
conf2.setAdvertisedAddress("localhost");
conf2.setClusterName(conf.getClusterName());
conf2.setLoadManagerClassName(ModularLoadManagerImpl.class.getName());
conf2.setZookeeperServers("localhost:2181");
PulsarService pulsar2 = startBroker(conf2);
// configure broker-1 with ModularLoadlManager
stopBroker();
conf.setLoadManagerClassName(ModularLoadManagerImpl.class.getName());
startBroker();
pulsar.getLoadManager().get().writeLoadReportOnZookeeper();
pulsar2.getLoadManager().get().writeLoadReportOnZookeeper();
LoadManager loadManager1 = spy(pulsar.getLoadManager().get());
LoadManager loadManager2 = spy(pulsar2.getLoadManager().get());
Field loadManagerField = NamespaceService.class.getDeclaredField("loadManager");
loadManagerField.setAccessible(true);
// (2) Make sure broker-2 always assign bundle to broker1
// mock: redirect request to leader [2]
doReturn(true).when(loadManager2).isCentralized();
loadManagerField.set(pulsar2.getNamespaceService(), new AtomicReference<>(loadManager2));
// mock: return Broker1 as a Least-loaded broker when leader receies request [3]
doReturn(true).when(loadManager1).isCentralized();
SimpleResourceUnit resourceUnit = new SimpleResourceUnit(pulsar.getWebServiceAddress(), null);
Optional<ResourceUnit> res = Optional.of(resourceUnit);
doReturn(res).when(loadManager1).getLeastLoaded(any(ServiceUnitId.class));
loadManagerField.set(pulsar.getNamespaceService(), new AtomicReference<>(loadManager1));
URI broker2ServiceUrl = new URI("pulsar://localhost:" + conf2.getBrokerServicePort());
PulsarClient pulsarClient2 = PulsarClient.builder().serviceUrl(broker2ServiceUrl.toString()).build();
// (3) Broker-2 receives topic-1 request, creates local-policies and sets the watch
final String topic1 = "persistent://" + namespace + "/topic1";
Consumer<byte[]> consumer1 = pulsarClient2.newConsumer().topic(topic1).subscriptionName("my-subscriber-name").subscribe();
Set<String> serviceUnits1 = pulsar.getNamespaceService().getOwnedServiceUnits().stream().map(nb -> nb.toString()).collect(Collectors.toSet());
// (4) Broker-1 will own topic-1
final String unsplitBundle = namespace + "/0x00000000_0xffffffff";
assertTrue(serviceUnits1.contains(unsplitBundle));
// broker-2 should have this bundle into the cache
TopicName topicName = TopicName.get(topic1);
NamespaceBundle bundleInBroker2 = pulsar2.getNamespaceService().getBundle(topicName);
assertEquals(bundleInBroker2.toString(), unsplitBundle);
// update broker-1 bundle report to zk
pulsar.getBrokerService().updateRates();
pulsar.getLoadManager().get().writeLoadReportOnZookeeper();
// this will create znode for bundle-data
pulsar.getLoadManager().get().writeResourceQuotasToZooKeeper();
pulsar2.getLoadManager().get().writeLoadReportOnZookeeper();
// (5) Modular-load-manager will split the bundle due to max-topic threshold reached
Field leaderField = LeaderElectionService.class.getDeclaredField("isLeader");
Method updateAllMethod = ModularLoadManagerImpl.class.getDeclaredMethod("updateAll");
updateAllMethod.setAccessible(true);
leaderField.setAccessible(true);
AtomicBoolean isLeader = (AtomicBoolean) leaderField.get(pulsar2.getLeaderElectionService());
isLeader.set(true);
ModularLoadManagerImpl loadManager = (ModularLoadManagerImpl) ((ModularLoadManagerWrapper) pulsar2.getLoadManager().get()).getLoadManager();
// broker-2 loadManager is a leader and let it refresh load-report from all the brokers
updateAllMethod.invoke(loadManager);
conf2.setLoadBalancerAutoBundleSplitEnabled(true);
conf2.setLoadBalancerAutoUnloadSplitBundlesEnabled(true);
conf2.setLoadBalancerNamespaceBundleMaxTopics(0);
loadManager.checkNamespaceBundleSplit();
// (6) Broker-2 should get the watch and update bundle cache
final int retry = 5;
for (int i = 0; i < retry; i++) {
if (pulsar2.getNamespaceService().getBundle(topicName).equals(bundleInBroker2) && i != retry - 1) {
Thread.sleep(200);
} else {
break;
}
}
// (7) Make lookup request again to Broker-2 which should succeed.
final String topic2 = "persistent://" + namespace + "/topic2";
Consumer<byte[]> consumer2 = pulsarClient.newConsumer().topic(topic2).subscriptionName("my-subscriber-name").subscribe();
NamespaceBundle bundleInBroker1AfterSplit = pulsar2.getNamespaceService().getBundle(TopicName.get(topic2));
assertFalse(bundleInBroker1AfterSplit.equals(unsplitBundle));
consumer1.close();
consumer2.close();
pulsarClient2.close();
pulsar2.close();
} finally {
conf.setLoadManagerClassName(loadBalancerName);
}
}
use of org.apache.pulsar.broker.loadbalance.LoadManager in project incubator-pulsar by apache.
the class BrokerServiceLookupTest method testPartitionTopicLookup.
/**
* Create #PartitionedTopic and let it served by multiple brokers which requries a. tcp partitioned-metadata-lookup
* b. multiple topic-lookup c. partitioned producer-consumer
*
* @throws Exception
*/
@Test
public void testPartitionTopicLookup() throws Exception {
log.info("-- Starting {} test --", methodName);
int numPartitions = 8;
TopicName topicName = TopicName.get("persistent://my-property/use/my-ns/my-partitionedtopic1");
admin.persistentTopics().createPartitionedTopic(topicName.toString(), numPartitions);
/**
** start broker-2 ***
*/
ServiceConfiguration conf2 = new ServiceConfiguration();
conf2.setAdvertisedAddress("localhost");
conf2.setBrokerServicePort(PortManager.nextFreePort());
conf2.setBrokerServicePortTls(PortManager.nextFreePort());
conf2.setWebServicePort(PortManager.nextFreePort());
conf2.setWebServicePortTls(PortManager.nextFreePort());
conf2.setAdvertisedAddress("localhost");
conf2.setClusterName(pulsar.getConfiguration().getClusterName());
conf2.setZookeeperServers("localhost:2181");
PulsarService pulsar2 = startBroker(conf2);
pulsar.getLoadManager().get().writeLoadReportOnZookeeper();
pulsar2.getLoadManager().get().writeLoadReportOnZookeeper();
LoadManager loadManager1 = spy(pulsar.getLoadManager().get());
LoadManager loadManager2 = spy(pulsar2.getLoadManager().get());
Field loadManagerField = NamespaceService.class.getDeclaredField("loadManager");
loadManagerField.setAccessible(true);
// mock: return Broker2 as a Least-loaded broker when leader receies request
doReturn(true).when(loadManager1).isCentralized();
loadManagerField.set(pulsar.getNamespaceService(), new AtomicReference<>(loadManager1));
// mock: redirect request to leader
doReturn(true).when(loadManager2).isCentralized();
loadManagerField.set(pulsar2.getNamespaceService(), new AtomicReference<>(loadManager2));
/**
** broker-2 started ***
*/
Producer<byte[]> producer = pulsarClient.newProducer().topic(topicName.toString()).messageRoutingMode(MessageRoutingMode.RoundRobinPartition).create();
Consumer<byte[]> consumer = pulsarClient.newConsumer().topic(topicName.toString()).subscriptionName("my-partitioned-subscriber").subscribe();
for (int i = 0; i < 20; i++) {
String message = "my-message-" + i;
producer.send(message.getBytes());
}
Message<byte[]> msg = null;
Set<String> messageSet = Sets.newHashSet();
for (int i = 0; i < 20; i++) {
msg = consumer.receive(5, TimeUnit.SECONDS);
assertNotNull(msg, "Message should not be null");
consumer.acknowledge(msg);
String receivedMessage = new String(msg.getData());
log.debug("Received message: [{}]", receivedMessage);
assertTrue(messageSet.add(receivedMessage), "Message " + receivedMessage + " already received");
}
producer.close();
consumer.unsubscribe();
consumer.close();
admin.persistentTopics().deletePartitionedTopic(topicName.toString());
pulsar2.close();
loadManager2 = null;
log.info("-- Exiting {} test --", methodName);
}
use of org.apache.pulsar.broker.loadbalance.LoadManager in project incubator-pulsar by apache.
the class BrokerServiceLookupTest method testWebserviceServiceTls.
/**
* 1. Start broker1 and broker2 with tls enable 2. Hit HTTPS lookup url at broker2 which redirects to HTTPS broker1
*
* @throws Exception
*/
@Test
public void testWebserviceServiceTls() throws Exception {
log.info("-- Starting {} test --", methodName);
final String TLS_SERVER_CERT_FILE_PATH = "./src/test/resources/certificate/server.crt";
final String TLS_SERVER_KEY_FILE_PATH = "./src/test/resources/certificate/server.key";
final String TLS_CLIENT_CERT_FILE_PATH = "./src/test/resources/certificate/client.crt";
final String TLS_CLIENT_KEY_FILE_PATH = "./src/test/resources/certificate/client.key";
/**
** start broker-2 ***
*/
ServiceConfiguration conf2 = new ServiceConfiguration();
conf2.setAdvertisedAddress("localhost");
conf2.setBrokerServicePort(PortManager.nextFreePort());
conf2.setBrokerServicePortTls(PortManager.nextFreePort());
conf2.setWebServicePort(PortManager.nextFreePort());
conf2.setWebServicePortTls(PortManager.nextFreePort());
conf2.setAdvertisedAddress("localhost");
conf2.setTlsAllowInsecureConnection(true);
conf2.setTlsEnabled(true);
conf2.setTlsCertificateFilePath(TLS_SERVER_CERT_FILE_PATH);
conf2.setTlsKeyFilePath(TLS_SERVER_KEY_FILE_PATH);
conf2.setClusterName(conf.getClusterName());
conf2.setZookeeperServers("localhost:2181");
PulsarService pulsar2 = startBroker(conf2);
// restart broker1 with tls enabled
conf.setTlsAllowInsecureConnection(true);
conf.setTlsEnabled(true);
conf.setTlsCertificateFilePath(TLS_SERVER_CERT_FILE_PATH);
conf.setTlsKeyFilePath(TLS_SERVER_KEY_FILE_PATH);
stopBroker();
startBroker();
pulsar.getLoadManager().get().writeLoadReportOnZookeeper();
pulsar2.getLoadManager().get().writeLoadReportOnZookeeper();
LoadManager loadManager1 = spy(pulsar.getLoadManager().get());
LoadManager loadManager2 = spy(pulsar2.getLoadManager().get());
Field loadManagerField = NamespaceService.class.getDeclaredField("loadManager");
loadManagerField.setAccessible(true);
// mock: redirect request to leader [2]
doReturn(true).when(loadManager2).isCentralized();
loadManagerField.set(pulsar2.getNamespaceService(), new AtomicReference<>(loadManager2));
// mock: return Broker2 as a Least-loaded broker when leader receies
// request [3]
doReturn(true).when(loadManager1).isCentralized();
SimpleResourceUnit resourceUnit = new SimpleResourceUnit(pulsar2.getWebServiceAddress(), null);
doReturn(Optional.of(resourceUnit)).when(loadManager1).getLeastLoaded(any(ServiceUnitId.class));
loadManagerField.set(pulsar.getNamespaceService(), new AtomicReference<>(loadManager1));
/**
** started broker-2 ***
*/
URI brokerServiceUrl = new URI("pulsar://localhost:" + conf2.getBrokerServicePort());
PulsarClient pulsarClient2 = PulsarClient.builder().serviceUrl(brokerServiceUrl.toString()).build();
final String lookupResourceUrl = "/lookup/v2/destination/persistent/my-property/use/my-ns/my-topic1";
// set client cert_key file
KeyManager[] keyManagers = null;
Certificate[] tlsCert = SecurityUtility.loadCertificatesFromPemFile(TLS_CLIENT_CERT_FILE_PATH);
PrivateKey tlsKey = SecurityUtility.loadPrivateKeyFromPemFile(TLS_CLIENT_KEY_FILE_PATH);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setKeyEntry("private", tlsKey, "".toCharArray(), tlsCert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, "".toCharArray());
keyManagers = kmf.getKeyManagers();
TrustManager[] trustManagers = InsecureTrustManagerFactory.INSTANCE.getTrustManagers();
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(keyManagers, trustManagers, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslCtx.getSocketFactory());
// hit broker2 url
URLConnection con = new URL(pulsar2.getWebServiceAddressTls() + lookupResourceUrl).openConnection();
log.info("orignal url: {}", con.getURL());
con.connect();
log.info("connected url: {} ", con.getURL());
// assert connect-url: broker2-https
assertEquals(con.getURL().getPort(), conf2.getWebServicePortTls());
InputStream is = con.getInputStream();
// assert redirect-url: broker1-https only
log.info("redirected url: {}", con.getURL());
assertEquals(con.getURL().getPort(), conf.getWebServicePortTls());
is.close();
pulsarClient2.close();
pulsar2.close();
loadManager1 = null;
loadManager2 = null;
}
use of org.apache.pulsar.broker.loadbalance.LoadManager in project incubator-pulsar by apache.
the class NonPersistentTopicTest method testLoadManagerAssignmentForNonPersistentTestAssignment.
/**
* verifies load manager assigns topic only if broker started in non-persistent mode
*
* <pre>
* 1. Start broker with disable non-persistent topic mode
* 2. Create namespace with non-persistency set
* 3. Create non-persistent topic
* 4. Load-manager should not be able to find broker
* 5. Create producer on that topic should fail
* </pre>
*/
@Test(dataProvider = "loadManager")
public void testLoadManagerAssignmentForNonPersistentTestAssignment(String loadManagerName) throws Exception {
final String namespace = "my-property/use/my-ns";
final String topicName = "non-persistent://" + namespace + "/loadManager";
final String defaultLoadManagerName = conf.getLoadManagerClassName();
final boolean defaultENableNonPersistentTopic = conf.isEnableNonPersistentTopics();
try {
// start broker to not own non-persistent namespace and create non-persistent namespace
stopBroker();
conf.setEnableNonPersistentTopics(false);
conf.setLoadManagerClassName(loadManagerName);
startBroker();
Field field = PulsarService.class.getDeclaredField("loadManager");
field.setAccessible(true);
@SuppressWarnings("unchecked") AtomicReference<LoadManager> loadManagerRef = (AtomicReference<LoadManager>) field.get(pulsar);
LoadManager manager = LoadManager.create(pulsar);
manager.start();
loadManagerRef.set(manager);
NamespaceBundle fdqn = pulsar.getNamespaceService().getBundle(TopicName.get(topicName));
LoadManager loadManager = pulsar.getLoadManager().get();
ResourceUnit broker = null;
try {
broker = loadManager.getLeastLoaded(fdqn).get();
} catch (Exception e) {
// Ok. (ModulearLoadManagerImpl throws RuntimeException incase don't find broker)
}
assertNull(broker);
try {
Producer<byte[]> producer = pulsarClient.newProducer().topic(topicName).createAsync().get(1, TimeUnit.SECONDS);
producer.close();
fail("topic loading should have failed");
} catch (Exception e) {
// Ok
}
NonPersistentTopic topicRef = (NonPersistentTopic) pulsar.getBrokerService().getTopicReference(topicName);
assertNull(topicRef);
} finally {
conf.setEnableNonPersistentTopics(defaultENableNonPersistentTopic);
conf.setLoadManagerClassName(defaultLoadManagerName);
}
}
use of org.apache.pulsar.broker.loadbalance.LoadManager in project incubator-pulsar by apache.
the class NonPersistentTopicTest method testNonPersistentBrokerModeRejectPersistentTopic.
/**
* verifies that broker started with onlyNonPersistent mode doesn't own persistent-topic
*
* @param loadManagerName
* @throws Exception
*/
@Test(dataProvider = "loadManager")
public void testNonPersistentBrokerModeRejectPersistentTopic(String loadManagerName) throws Exception {
final String namespace = "my-property/use/my-ns";
final String topicName = "persistent://" + namespace + "/loadManager";
final String defaultLoadManagerName = conf.getLoadManagerClassName();
final boolean defaultEnablePersistentTopic = conf.isEnablePersistentTopics();
final boolean defaultEnableNonPersistentTopic = conf.isEnableNonPersistentTopics();
try {
// start broker to not own non-persistent namespace and create non-persistent namespace
stopBroker();
conf.setEnableNonPersistentTopics(true);
conf.setEnablePersistentTopics(false);
conf.setLoadManagerClassName(loadManagerName);
startBroker();
Field field = PulsarService.class.getDeclaredField("loadManager");
field.setAccessible(true);
@SuppressWarnings("unchecked") AtomicReference<LoadManager> loadManagerRef = (AtomicReference<LoadManager>) field.get(pulsar);
LoadManager manager = LoadManager.create(pulsar);
manager.start();
loadManagerRef.set(manager);
NamespaceBundle fdqn = pulsar.getNamespaceService().getBundle(TopicName.get(topicName));
LoadManager loadManager = pulsar.getLoadManager().get();
ResourceUnit broker = null;
try {
broker = loadManager.getLeastLoaded(fdqn).get();
} catch (Exception e) {
// Ok. (ModulearLoadManagerImpl throws RuntimeException incase don't find broker)
}
assertNull(broker);
try {
Producer<byte[]> producer = pulsarClient.newProducer().topic(topicName).createAsync().get(1, TimeUnit.SECONDS);
producer.close();
fail("topic loading should have failed");
} catch (Exception e) {
// Ok
}
NonPersistentTopic topicRef = (NonPersistentTopic) pulsar.getBrokerService().getTopicReference(topicName);
assertNull(topicRef);
} finally {
conf.setEnablePersistentTopics(defaultEnablePersistentTopic);
conf.setEnableNonPersistentTopics(defaultEnableNonPersistentTopic);
conf.setLoadManagerClassName(defaultLoadManagerName);
}
}
Aggregations