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

Update Broker service configuration dynamically #186

Merged
merged 5 commits into from
Mar 5, 2017

Conversation

rdhabalia
Copy link
Contributor

Motivation

as discussed at #184 : sometime it requires to update Broker-serviceConfiguration dynamically with the help of generic api.

Modifications

  • Annotation which defines service-configuration is dynamic
  • znode which contains map of dynamic serviceConfiguration's name and value
  • REST/AdminTool api to update specific dynamic-configuration by passing name/value
  • API to register listener which can be notified on config value change

Result

Broker can update serviceConfiguration dynamically and can execute appropriate action on configuration-value change.

@rdhabalia rdhabalia added type/enhancement The enhancements for the existing features or docs. e.g. reduce memory usage of the delayed messages type/feature The PR added a new feature or issue requested a new feature labels Feb 1, 2017
@rdhabalia rdhabalia added this to the 1.17 milestone Feb 1, 2017
@rdhabalia rdhabalia self-assigned this Feb 1, 2017
@rdhabalia rdhabalia force-pushed the dyn_conf branch 7 times, most recently from e7ba703 to 206ba5d Compare February 3, 2017 19:14
Copy link
Contributor

@merlimat merlimat left a comment

Choose a reason for hiding this comment

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

Change looks good. A couple of comments:

  • We should make very clear that the configuration in ZK overrides whatever is on the host config file. Eg: when we startup we should printing info log of what config we found on ZK

  • We should have 2 way of using dynamic fields

    • Either we keep reading the value from ServiceConfiguration and thus at some point we pick up the updated value. We don't need mutexes, since there's no strict requirement on change visibility.
    • Or we register the listener

* @param configValue
* : configuration value
*/
private void updateServiecConfiguration(String configName, String configValue) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo in updateServiecConfiguration

*/
private void updateServiecConfiguration(String configName, String configValue) {
try {
Field field = ServiceConfiguration.class.getDeclaredField(configName);
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of doing the reflection check on each request, could we doing just once (at startup) and keep a Set<> of keys that are dynamically updatable?

@@ -62,6 +62,7 @@
private long zooKeeperSessionTimeoutMillis = 30000;
// Time to wait for broker graceful shutdown. After this time elapses, the
// process will be killed
@FieldContext(dynamic = true)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd leave this PR to implement the "mechanism" and then we can make the actual variables dynamic in subsequent PRs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but in order to write test-cases and perform testing of this feature I take one of this simple attribute in this PR. It helps to write e2e testcases for this feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure


/**
* Update dynamic-ServiceConfiguration with value present into zk-configuraiton-map and register listeners on
* dynamic-ServiceConfiguration field to take appropriate action on change of zk-configuraiton-map.
Copy link
Contributor

Choose a reason for hiding this comment

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

zk-configuration-map

// update brokerShutdownTimeoutMs value on listener notification
registerConfigurationListener("brokerShutdownTimeoutMs", new Consumer<String>() {
@Override
public void accept(String shutdownTime) {
Copy link
Contributor

Choose a reason for hiding this comment

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

can abbreviate into a lambda here

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, for this example, we shouldn't even need to register for notification, right?

We should make sure that the value ServiceConfiguration instance is updated, and then always read it from there, instead of caching it in a variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, for this example, we shouldn't even need to register for notification, right?

Actually, we are not updating ServiceConfiguration instance's field value but we are calling registered listener for this field and it's registered-listener's responsibility to update the value and take appropriate action.
Because in case of #181 : Only when lookupRequestPermits field-value changes we want to take certain action such as update Semaphore's permits. Now, we have watch on entire dynamicConfigMap and listener can be triggered on every configKey-value change. So, registered listener can compare existing value and new value, and if it's changed then it can take appropriate action and update ServiceConfiguration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed it on commit can you please take a look of it.

* @param listener
* : listener which takes appropriate action on config-value change
*/
public void registerConfigurationListener(String configKey, Consumer<String> listener) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the listener to be working for string, ints, longs? (Maybe leveraging the FieldParser)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, but we can have non-primitive ParameterizedTypes also for which we have to pass Field to parse the value. So, made appropriate change.

field.setAccessible(true);
field.set(pulsar().getConfiguration(), FieldParser.value(value,field));
if (log.isDebugEnabled()) {
log.debug("Successfully updated {}/{}", key, value);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should print a info log line, for all the overridden variables

CmdBrokers(PulsarAdmin admin) {
super("brokers", admin);
jcommander.addCommand("list", new List());
jcommander.addCommand("namespaces", new Namespaces());
jcommander.addCommand("updateConfig", new UpdateConfigurationCmd());
Copy link
Contributor

Choose a reason for hiding this comment

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

we've been using - as separator in other commands. eg: update-config

@rdhabalia rdhabalia force-pushed the dyn_conf branch 2 times, most recently from 3593728 to f4adac9 Compare February 21, 2017 02:31
@rdhabalia
Copy link
Contributor Author

@merlimat : addressed all the changes, added one more change:
ConfigRegistered should be triggered only if the configValue has been changed
any thought?

Copy link
Contributor

@merlimat merlimat left a comment

Choose a reason for hiding this comment

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

Change looks very good, just a couple of minor comments

@@ -62,6 +62,7 @@
private long zooKeeperSessionTimeoutMillis = 30000;
// Time to wait for broker graceful shutdown. After this time elapses, the
// process will be killed
@FieldContext(dynamic = true)
Copy link
Contributor

Choose a reason for hiding this comment

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

Sure

@@ -48,9 +48,23 @@ void run() throws Exception {
}
}

@Parameters(commandDescription = "Update dynamic-serviceConfiguration of broker")
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we also add a command to get the list of "updatable" config fields?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, it would be useful to have command to print all the config that are stored in ZK. To know what is being overridden.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added both commands:

  • getUpdatableConfigName
  • getAllConfigurations to get key,value for all configs

* @param value
* @throws PulsarAdminException
*/
void updateConfiguration(String configName, String configValue) throws PulsarAdminException;
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of "updating" configuration, in this case we would be effectively "overriding" the local broker configuration with a "more important" configuration stored in ZK

Copy link
Contributor Author

@rdhabalia rdhabalia Mar 2, 2017

Choose a reason for hiding this comment

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

so, you mean we should rename the method to overrideDynamicConfiguration or we want to make any functionality change?

Copy link
Contributor

Choose a reason for hiding this comment

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

Just renaming. I'm not 100% sure about the name, just wanted to make clear that it doesn't update the config in a broker, rather it writes config in ZK that supersedes whatever all the brokers have locally.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updateDynamicConfigurationInZk, persistDynamicConfigValue, storeDynamicConfigValue ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have updated the document to call it out clearly and also renamed it as updateDynamicConfiguration. Do you think if we rename it to something else.?

getPermitZkNodeMethod.setAccessible(true);
getPermitZkNodeMethod.invoke(pulsar.getBrokerService());
// verify value is updated
assertEquals(pulsar.getConfiguration().getBrokerShutdownTimeoutMs(), shutdownTime);
Copy link
Contributor

Choose a reason for hiding this comment

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

The notification from ZK might be delayed in the background thread. In addition since we're doing "dirty" reads (avoid synchronization), it might take a bit more after the new value is visible on the getter method. We should have a retry loop here in the test to give a bit of time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have added this logic in testUpdateDynamicConfigurationWithZkWatch.
This test-case directly triggers registerListener because pulsarService started when znode was not created and can't set the watch if node is not exist. so, in this testcase it explicitly triggers registerListener call.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, tough is there also the other test that work with the zk watch and verifies we apply the change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, testUpdateDynamicConfigurationWithZkWatch first creates znode and any further config change happens by zk-watch. I have added retry loop there to wait for refreshed value.

public void testUpdateDynamicLocalConfiguration() throws Exception {

// (1) try to update dynamic field
final long shutdownTime = 10;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we verify that shutdown time is != 10 in the initial config?

@rdhabalia rdhabalia force-pushed the dyn_conf branch 5 times, most recently from 224004d to 67a124e Compare March 3, 2017 22:15
@rdhabalia rdhabalia force-pushed the dyn_conf branch 3 times, most recently from 691ccb0 to 012a47b Compare March 3, 2017 23:07
@rdhabalia
Copy link
Contributor Author

@merlimat I have also added AdminTools documentation change in this PR.
As we have PR dependencies #274 -> #181 -> this PR. we can merge it if we are fine with the changes.

Copy link
Contributor

@merlimat merlimat left a comment

Choose a reason for hiding this comment

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

👍

@merlimat merlimat merged commit 92b79d0 into apache:master Mar 5, 2017
@rdhabalia rdhabalia deleted the dyn_conf branch June 21, 2017 18:54
sijie pushed a commit to sijie/pulsar that referenced this pull request Mar 4, 2018
hrsakai pushed a commit to hrsakai/pulsar that referenced this pull request Dec 10, 2020
* Expose EventTime consistently as a non-pointer

* Expanded docs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/enhancement The enhancements for the existing features or docs. e.g. reduce memory usage of the delayed messages type/feature The PR added a new feature or issue requested a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants