Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[improve][admin,broker] Add option to unloadNamespaceBundle with bundle Affinity broker url #7

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

vineeth1995
Copy link
Owner

Motivation

To provide an option for admin to unload namespace bundle with broker url to which the bundle has to be assigned to after the unload.

Modifications

  1. Add an option to provide brokerWebServiceAddress (Ex: https://broker1.com:4443) while unloadingNamespaceBundle in the admin CLI and make corresponding changes in the pulsar-client-admin-api to support this.

  2. Changes in pulsar-broker unloadNamespaceBundle API to accommodate broker url while unloading.

  3. Add functionality in LoadManger implementation to select affinity broker for a bundle while trying to assign unloaded bundle to broker.

Verifying this change

This change added tests and can be verified as follows:

  • Added end to test to make sure the bundle assignment happens as per the expectation

Does this pull request potentially affect one of the following parts:

If the box was checked, please highlight the changes

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • Anything that affects deployment

Documentation

  • doc
  • doc-required
  • doc-not-needed
  • doc-complete

Matching PR in forked repository

PR in forked repository:

@vineeth1995 vineeth1995 changed the title Bundle unload [improve][admin,broker] Add option to unloadNamespaceBundle with bundle Affinity broker url Nov 7, 2022
Copy link

@rdhabalia rdhabalia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM . minor comments.

if (destinationBroker != null) {
if (!this.isLeaderBroker()) {
LeaderBroker leaderBroker = pulsar().getLeaderElectionService().getCurrentLeader().get();
String leaderBrokerUrl = leaderBroker.getServiceUrl();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will not work in case of https. we need to select URL based on the request type HTTP or HTTPS?
you can find reference at: https://github.com/apache/pulsar/blob/master/pulsar-broker/src/main/java/org/apache/pulsar/broker/lookup/TopicLookupBase.java#L104

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will work based on incoming requests ( http or https).

String leaderBrokerUrl = leaderBroker.getServiceUrl();
try {
URL redirectUrl = new URL(leaderBrokerUrl);
URI redirect = UriBuilder.fromUri(uri.getRequestUri()).host(redirectUrl.getHost())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, it's better to separate out this logic in a separate method
eg: validateLeader(httpRequest) this sends redirect response by throwing temporaryRedirect-Exception if current broker is not leader.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

false).build();

// Redirect
log.debug("Redirecting the rest call to leader - {}, bundleRange - {}", redirect, bundleRange);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

always try to keep log.debug under if -> if(log.isDebugEnabled)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -886,8 +886,10 @@ public void unloadNamespace(@Suspended final AsyncResponse asyncResponse, @PathP
public void unloadNamespaceBundle(@Suspended final AsyncResponse asyncResponse,
@PathParam("property") String property, @PathParam("cluster") String cluster,
@PathParam("namespace") String namespace, @PathParam("bundle") String bundleRange,
@QueryParam("authoritative") @DefaultValue("false") boolean authoritative) {
@QueryParam("authoritative") @DefaultValue("false") boolean authoritative,
@QueryParam("destinationBroker") String destinationBroker) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to update the doc in admin-api-topics.md file

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -854,6 +855,29 @@ protected BookieAffinityGroupData internalGetBookieAffinityGroup() {
}
}

public void setNamespaceBundleAffinity (String bundleRange, String destinationBroker) {
if (destinationBroker != null) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to avoid nested if cyclomatic complexity. instead do

if (StringUtils.isBlank(destinationBroker)) {
  return;
}

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed


void setNamespaceBundleAffinity(String bundle, String broker);

String removeNamespaceBundleAffinity(String bundle);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally, if we have set api then we can avoid delete API. do we really need delete API? can we just call set with null value for removing affinity.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removeNamespaceBundleAffinity also serves the purpose of get heree

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean instead of calling remove, can we just call set(bundle, null) -> null broker means remove affinity.?

@rdhabalia
Copy link

test-case failure

 Error:  Tests run: 7, Failures: 1, Errors: 0, Skipped: 6, Time elapsed: 31.675 s <<< FAILURE! - in org.apache.pulsar.broker.stats.MetadataStoreStatsTest
  Error:  testBatchMetadataStoreMetrics(org.apache.pulsar.broker.stats.MetadataStoreStatsTest)  Time elapsed: 10.762 s  <<< FAILURE!
  java.lang.AssertionError: expected object to not be null
  	at org.testng.Assert.fail(Assert.java:99)
  	at org.testng.Assert.assertNotNull(Assert.java:942)
  	at org.testng.Assert.assertNotNull(Assert.java:926)
  	at org.apache.pulsar.broker.stats.MetadataStoreStatsTest.testBatchMetadataStoreMetrics(MetadataStoreStatsTest.java:185)

can you verify if it's failing for you as well

@vineeth1995
Copy link
Owner Author

test-case failure

 Error:  Tests run: 7, Failures: 1, Errors: 0, Skipped: 6, Time elapsed: 31.675 s <<< FAILURE! - in org.apache.pulsar.broker.stats.MetadataStoreStatsTest
  Error:  testBatchMetadataStoreMetrics(org.apache.pulsar.broker.stats.MetadataStoreStatsTest)  Time elapsed: 10.762 s  <<< FAILURE!
  java.lang.AssertionError: expected object to not be null
  	at org.testng.Assert.fail(Assert.java:99)
  	at org.testng.Assert.assertNotNull(Assert.java:942)
  	at org.testng.Assert.assertNotNull(Assert.java:926)
  	at org.apache.pulsar.broker.stats.MetadataStoreStatsTest.testBatchMetadataStoreMetrics(MetadataStoreStatsTest.java:185)

can you verify if it's failing for you as well

Yes, it passes for me in the local

String leaderBrokerUrl = leaderBroker.getServiceUrl();
try {
URL redirectUrl = new URL(leaderBrokerUrl);
URI redirect = UriBuilder.fromUri(uri.getRequestUri()).host(redirectUrl.getHost())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it always returns http?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't it be based on http-request that comes from user . I guess I gave code reference earlier?

Copy link
Owner Author

@vineeth1995 vineeth1995 Nov 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here uri is the input request uri. So if the input request has https, uri. getRequestUri() returns https url and we are only replacing host and port. The same is being used here.

return UriBuilder.fromUri(uri.getRequestUri()).host(webUrl.getHost()).port(webUrl.getPort()).build();

Copy link

@rdhabalia rdhabalia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. minor comments. you can address them and can create PR in open source.


// Redirect
if (log.isDebugEnabled()) {
log.debug("Redirecting the rest call to leader - {}", redirect);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redirecting the request call to leader

@@ -710,8 +710,8 @@ public CompletableFuture<Void> validateBundleOwnershipAsync(NamespaceBundle bund
// Replace the host and port of the current request and redirect
URI redirect = UriBuilder.fromUri(uri.getRequestUri()).host(webUrl.get().getHost())
.port(webUrl.get().getPort()).replaceQueryParam("authoritative",
newAuthoritative).build();

newAuthoritative).replaceQueryParam("destinationBroker",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if destinationBroker is optional then if we don't pass it then by default value will be null. so, is it necessary to pass null value for destinationBroker ? or can we just make any change here if we are any passing null value?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are replacing the param with null because if destination broker is not null in the input request, it will again try to call leader broker to add the input to bundle affinity map which is already done before this step.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it.

@Override
void run() throws PulsarAdminException {
String namespace = validateNamespace(params);
if (bundle == null) {
getAdmin().namespaces().unload(namespace);
} else {
getAdmin().namespaces().unloadNamespaceBundle(namespace, bundle);
if (destinationBroker == null) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should avoid if/else here. what if we just call unloadNamespaceBundle with null destination. As it's passed as a query-param, server is anyway ignoring the value of destinationBroker if it has null value. right?

getAdmin().namespaces().unloadNamespaceBundle(namespace, bundle, destinationBroker);

Vineeth added 13 commits December 20, 2022 22:04
@github-actions
Copy link

The pr had no activity for 30 days, mark with Stale label.

@github-actions github-actions bot added the Stale label Jan 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants