Skip to content

KAFKA-13689: Optimized the printing of AbstractConfig logs, and stripped unknownKeys from unusedKeys#11800

Merged
showuon merged 32 commits intoapache:trunkfrom
RivenSun2:KAFKA-13689
Mar 5, 2022
Merged

KAFKA-13689: Optimized the printing of AbstractConfig logs, and stripped unknownKeys from unusedKeys#11800
showuon merged 32 commits intoapache:trunkfrom
RivenSun2:KAFKA-13689

Conversation

@RivenSun2
Copy link
Copy Markdown
Contributor

Optimized the printing of AbstractConfig logs, and stripped unknownKeys from unusedKeys

RivenSun2 and others added 27 commits September 19, 2021 17:59
… cpu and traffic on the broker side increase sharply

JIRA link : https://issues.apache.org/jira/browse/KAFKA-13310

Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
…sets method

JIRA link : https://issues.apache.org/jira/browse/KAFKA-13310

Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
2. Optimize the import of package

Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
add test Method "testForceMetadataDeleteForPatternSubscriptionDuringRebalance()"

Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
Author: RivenSun2 <riven.sun@zoom.us>

Reviewers: Luke Chen <showuon@gmail.com>
Author: RivenSun2 riven.sun@zoom.us
� Conflicts:
�	clients/src/test/java/org/apache/kafka/clients/consumer/KafkaConsumerTest.java
@RivenSun2
Copy link
Copy Markdown
Contributor Author

Hi @showuon @guozhangwang
Please help to review the PR .
Thanks.

Copy link
Copy Markdown
Member

@showuon showuon left a comment

Choose a reason for hiding this comment

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

@RivenSun2 , thanks for the PR. Left some comments.

for (String key : unused())
Set<String> unusedKeys = unused();
//Printing unusedKeys to users should remove unknownKeys
unusedKeys.removeAll(unknown());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we move this remove unknown keys into unUsed method, and let logUnused only do the log thing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't want to change the existing behavior of unused() method, otherwise many testCases in AbstractConfigTest will fail.
Only when printing unusedKeys to the user, tell the user exactly which configurations are known but unused

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For KafkaClient, unknownKeys also belong to unusedKeys, what do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Before this PR, the unUsed set contains both unUsed and unKnown configs, because we didn't separate them.
After this PR, we hope we can separate the unUsed and unKnown, so we created a new method unKnown. Under this situation, I don't think it makes sense to make unUsed set contains both unUsed and unKnown. That will just confuse other developers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ok, I agree with you.

props.put(unknownTestConfig, "my_value");
ConsumerConfig config = new ConsumerConfig(ConsumerConfig.appendDeserializerToConfig(props, new StringDeserializer(), new StringDeserializer()));

assertTrue(config.unknown().contains(unknownTestConfig));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also verify the config.unknown() has only 1 element, that is: unknownTestConfig. In current verification, there could be many unknown in the configs, but still pass the test. Same as below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree with you,thanks.

}

@Test
public void testUnknownConfigs() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also test the mix of unknown and unused configs case, because we have some logic for them, right?

Copy link
Copy Markdown
Contributor Author

@RivenSun2 RivenSun2 Feb 24, 2022

Choose a reason for hiding this comment

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

In fact, I don't recommend changing the current logic of the unused method, because for KafkaClient, unknownKeys also belong to unusedKeys, what do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we can add the mix of unknown and unused test case, no matter we want to change unused logics or not. That is, like the previous testUnusedConfigs test, we can add an unknown configs into it, and verify the unUsed and unknown results are as what we expected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure,I will add.

Comment on lines +815 to +816
config.logUnused();
config.logUnknown();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's a little weird and easy to forget to call these 2 methods after client initialization. Could we create a public logUnknownAndUnused method, and make both logUnused and logUnknown as private, so that users will always call logUnknownAndUnused to log both. WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

@showuon
Thank you for your review, please check when you are available.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

RivenSun2 commented Feb 24, 2022

@showuon
Please help to check when you are available.
Thanks.

Copy link
Copy Markdown
Member

@showuon showuon left a comment

Choose a reason for hiding this comment

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

@RivenSun2 , thanks for the update. Left some comments.


assertTrue(config.unused().contains(SslConfigs.SSL_PROTOCOL_CONFIG));
assertTrue(config.unknown().contains(unknownTestConfig));
assertEquals(1, config.unknown().size());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should also assert the unUsed().size() == 1.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In fact, unused.size is not 1, I will add assert for it later.

assertTrue(config.unused().contains("sasl.mechanism"));
assertEquals("GSSAPI", valuesWithPrefixOverride.get("sasl.mechanism"));
assertFalse(config.unused().contains("sasl.mechanism"));
assertFalse(config.unused().contains("prefix.sasl.mechanism"));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

here, we should change to assert unknown, right?
Same as below.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we add
assertFalse(config.unknown().contains("prefix.sasl.mechanism"));
here? Because we assert unknown before using prefix.sasl.mechanism config (i.e. valuesWithPrefixOverride.get("sasl.mechanism")), we should expect prefix.sasl.mechanism is not unknown after using it, right?

Copy link
Copy Markdown
Member

@showuon showuon left a comment

Choose a reason for hiding this comment

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

Thanks for the update. Left some comments.

Comment on lines +2861 to +2862
assertEquals(1, config.unknown().size());
assertEquals(3, config.unused().size());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I these assert here is not meaningful. We can remove them and keep the asserts after consumer created below.

assertTrue(config.unused().contains(SslConfigs.SSL_PROTOCOL_CONFIG));
assertTrue(config.unknown().contains(unknownTestConfig));
assertEquals(1, config.unknown().size());
assertEquals(4, config.unused().size());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here, we can just keep the asserts after consumer created

Comment on lines +1865 to +1866
assertEquals(1, config.unknown().size());
assertEquals(3, config.unused().size());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same as here, and other places

assertTrue(config.unused().contains("sasl.mechanism"));
assertEquals("GSSAPI", valuesWithPrefixOverride.get("sasl.mechanism"));
assertFalse(config.unused().contains("sasl.mechanism"));
assertFalse(config.unused().contains("prefix.sasl.mechanism"));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we add
assertFalse(config.unknown().contains("prefix.sasl.mechanism"));
here? Because we assert unknown before using prefix.sasl.mechanism config (i.e. valuesWithPrefixOverride.get("sasl.mechanism")), we should expect prefix.sasl.mechanism is not unknown after using it, right?

assertFalse(config.unused().contains("sasl.kerberos.kinit.cmd"));
assertEquals("/usr/bin/kinit2", valuesWithPrefixOverride.get("sasl.kerberos.kinit.cmd"));
assertFalse(config.unused().contains("sasl.kerberos.kinit.cmd"));
assertFalse(config.unused().contains("prefix.sasl.kerberos.kinit.cmd"));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same here and below, we should assert false to (config.unknown().contains("prefix.sasl.kerberos.kinit.cmd") after using that config.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

Hi @showuon Thank you for your reply.
In fact, in the AbstractConfigTest class, I have asserted unknown() after config.valuesWithPrefixOverride(prefix).
valuesWithPrefixOverride is just a normal map, which is returned by config.valuesWithPrefixOverride(prefix).
valuesWithPrefixOverride.get(xxxx) no longer affects config.

@showuon
Copy link
Copy Markdown
Member

showuon commented Feb 25, 2022

Hi @showuon Thank you for your reply. In fact, in the AbstractConfigTest class, I have asserted unknown() after config.valuesWithPrefixOverride(prefix). valuesWithPrefixOverride is just a normal map, which is returned by config.valuesWithPrefixOverride(prefix). valuesWithPrefixOverride.get(xxxx) no longer affects config.

@RivenSun2 , are you saying there will be some configs that are not in unused configs, but will be in unknown configs? Does that make sense? Some configs are unknown but are used in Kafka? It doesn't sound correct to me.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

@showuon
you misunderstood me

  1. A configuration is in unknown(), then it must not be in unused()
  2. A configuration is not in unknown(), then it may be in unused()
  3. A configuration is in unused(), then it must not be in unknown()
  4. A configuration may be neither in unused() nor unknown() because it is usedKey.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

RivenSun2 commented Feb 25, 2022

In fact, in the testcases we discussed in AbstractConfigTest, config.unused() and config.unknown() will not change after TestSecurityConfig config is initialized.
The following config.valuesWithPrefixOverride(prefix) and valuesWithPrefixOverride.get(xxxx) will not cause the return value of unused() and unknown() to change.

The main purpose of these testCases is to test whether the Map value returned by AbstractConfig#valuesWithPrefixOverride meets our expectations under different conditions.

Thanks.

@showuon
Copy link
Copy Markdown
Member

showuon commented Feb 25, 2022

In fact, in the testcases we discussed, config.unused() and config.unknown() will not change after TestSecurityConfig config is initialized. The following config.valuesWithPrefixOverride(prefix) and valuesWithPrefixOverride.get(xxxx) will not cause the return value of unused() and unknown() to change

Thanks for the explanation. But I don't think it is correct. If we check the original test below in testValuesWithPrefixOverride

       // prefix overrides global
        assertTrue(config.unused().contains("prefix.sasl.mechanism"));
        assertTrue(config.unused().contains("sasl.mechanism"));
        assertEquals("GSSAPI", valuesWithPrefixOverride.get("sasl.mechanism"));
        assertFalse(config.unused().contains("sasl.mechanism"));
        assertFalse(config.unused().contains("prefix.sasl.mechanism"));

We can see the unused was expected to contain those 2 configs. Then after valuesWithPrefixOverride.get("sasl.mechanism"), they are used now, that is, not containing in unused set.
So, what I mean is that since we've changed the 1st assert into unknown:

assertTrue(config.unknown().contains("prefix.sasl.mechanism"));

Theh, we should change the last assert to assert unknown there:

assertFalse(config.unknown().contains("prefix.sasl.mechanism"));

Does that make sense?

@RivenSun2
Copy link
Copy Markdown
Contributor Author

@showuon
Sorry, I made a mistake, the map returned by config.valuesWithPrefixOverride(prefix) is not a normal map, it is of type AbstractConfig.RecordingMap.
RecordingMap#get(Object key) will call the AbstractConfig#ignore(String key) method to change the AbstractConfig.used variable.
Forgive my mistakes.

However, after valuesWithPrefixOverride.get("sasl.mechanism") add assertFalse(config.unknown().contains("prefix.sasl.mechanism"));,
testCase will fail to verify; because unknownKeys is only affected by originals and values, the value is originalKeys.removeAll(valueKeys).

@showuon
Copy link
Copy Markdown
Member

showuon commented Feb 26, 2022

However, after valuesWithPrefixOverride.get("sasl.mechanism") add assertFalse(config.unknown().contains("prefix.sasl.mechanism"));,
testCase will fail to verify; because unknownKeys is only affected by originals and values, the value is originalKeys.removeAll(valueKeys).

So, could we also remove used config keys for unknown configs? Otherwise, there would be this strange case that a config is used, but unknown to kafka.

Thanks.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

Hi @showuon
Currently the logic of the unknown() method is exactly what you would expect.
unknownKeys=originalKeys.removeAll(valueKeys)

unknownKeys contains neither usedKeys nor unusedKeys.
Only configKeys that are not officially recognized by kafka will be put into unknownKeys.
Thanks.

@showuon
Copy link
Copy Markdown
Member

showuon commented Feb 26, 2022

unknownKeys contains neither usedKeys nor unusedKeys.
Only configKeys that are not officially recognized by kafka will be put into unknownKeys.

Yes, this is what I expected. Thanks.
But that also confuses me: if unknown keys doesn't contain used and unused, why this test will fail after we assert unknown?

However, after valuesWithPrefixOverride.get("sasl.mechanism") add assertFalse(config.unknown().contains("prefix.sasl.mechanism"));,
testCase will fail to verify; because unknownKeys is only affected by originals and values, the value is originalKeys.removeAll(valueKeys).

In the above test case, we originally expect that prefix.sasl.mechanism is used and is not in unused keys. After this PR, we should expected that prefix.sasl.mechanism is used, and not in unused and NOT in unknown keys, right? Did I miss anything here?
Thanks.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

RivenSun2 commented Feb 26, 2022

@showuon I totally agree with you now. It was I forgot to modify a code that caused it to not meet our expectations.
In the methods AbstractConfig#ignore(String key) and AbstractConfig#get(String key), add the following logic before used.add(key) :

if (!unknown().contains(key))
used.add(key);

What do you think?
Thanks.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

Or we add an instance variable AbstractConfig.unknownKeys, we can complete the assignment to the variable unknownKeys when AbstractConfig is initialized.
unknownKeys = originals.keySet().removeAll(values.keySet())
unknownKeys should not be changed after AbstractConfig is initialized.

In this way, in the unknown() method, we directly return unknownKeys to avoid recalculating unknownKeys each time.
What do you think?
Thanks.

@showuon
Copy link
Copy Markdown
Member

showuon commented Feb 26, 2022

if (!unknown().contains(key)) {
used.add(key);
}

The reason we call ignore is because we indeed use this config key. In your logic, it'll make the used config keys not existed in used set (when it's unknown). It will confuse other developers, even though we can make the test pass.
I think we should remove all used keys in unknown method. That will exclude all used keys when retrieving unknown config keys. WDYT?

@RivenSun2
Copy link
Copy Markdown
Contributor Author

@showuon
okay, I agree with you. This is probably better than what I said above.
I will resubmit later, thanks for your suggestion.

@showuon
Copy link
Copy Markdown
Member

showuon commented Feb 26, 2022

unknownKeys = originals.keySet().removeAll(values.keySet())
unknownKeys should not be changed after AbstractConfig is initialized.

That looks good, but I think that doesn't work in some cases, like the prefix case.
I'm not very familiar with the prefix logic, but I think the prefix is dynamic added to the config key. So that would make your assumption (unknownKeys should not be changed after AbstractConfig is initialized) failed. Could you make sure if your logic works in dynamic prefix case? (i.e. the testValuesWithPrefixOverride test case or other similar one)

Thanks.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

@showuon
I agree with you now, thank you for your suggestion.
Thanks again.

Copy link
Copy Markdown
Member

@showuon showuon left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for the PR! I'll wait for another week to see if there are other people also want to have a review. Thanks.

@showuon showuon merged commit 0dac4b4 into apache:trunk Mar 5, 2022
@showuon
Copy link
Copy Markdown
Member

showuon commented Mar 5, 2022

@RivenSun2 , thanks for the contribution!

log.info(b.toString());
}

public void logUnusedAndUnknown() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh... Thanks for the reminder. @RivenSun2 , could you summit a small KIP for this change? Thanks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Did we consider the fact that we don't know the config names for pluggable components?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

TBH, no, I've never considered that! Thanks for the reminder.

@RivenSun2 , sorry, I forgot the AbstractConfig is a public API. But since the v3.2.0 KIP freeze has passed, and I think this KIP might need more discussion, could you submit another PR to revert this change first? After KIP discussion/voting passed, we can start to work on it again. If you don't have time to submit a revert PR within this week, please let me know. Thank you.

@RivenSun2
Copy link
Copy Markdown
Contributor Author

Hi @showuon
I will create a new PR later to revert this code change.
Will the new PR title start with MINOR or still start with KAFKA-13689?
For the configuration of some pluggable components of KafkaClients, will Kafka not know the specific configuration name? could you give an example?
Thanks.

@showuon
Copy link
Copy Markdown
Member

showuon commented Mar 8, 2022

@RivenSun2 , thanks for the help.

Will the new PR title start with MINOR or still start with KAFKA-13689?

Let's start with KAFKA-13689.

For the configuration of some pluggable components of KafkaClients, will Kafka not know the specific configuration name? could you give an example?

Something like KIP-519. Let's discuss it in KIP discussion. Thanks.

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants