-
Notifications
You must be signed in to change notification settings - Fork 34
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
Fix partition key computation for aggregation #158
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comments for code review
if !hasPartitionKey { | ||
if len(a.partitionKeys) > 0 { | ||
// Take the first partition key from the map, if any | ||
for k, _ := range a.partitionKeys { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm open to suggestions for how to do this better, not sure how to get keys out of a map properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could I ask a question about what "first" means here? Does it mean the first element/key was put in the map? Then I am not sure if you could get it from the map through iteration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I generally just want any key that is in the map, basically we choose a "random" key for the record but AFAICT this key does not matter, since the real partition key is just the first key, so this is just a way to save space. I'll update the comment.
} | ||
// Recompute field size, since it changed | ||
pKeyIdx, _ = a.checkPartitionKey(partitionKey) | ||
pkeyFieldSize = protowire.SizeVarint(pKeyIdx) + fieldNumberSize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also fixes a sizing bug, when we switch records we may be off on the size slightly (it may shrink if the previous pkeyIdx
was > 128
)
to be even clearer, the event sequence we were seeing was
This is because the second |
oh, no, this was a separate bug we found today :) #155 is perfectly fine on it's own |
Thanks for confirming. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, could I double check that you've tested the code change in an end-to-end test right?
if !hasPartitionKey { | ||
if len(a.partitionKeys) > 0 { | ||
// Take the first partition key from the map, if any | ||
for k, _ := range a.partitionKeys { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could I ask a question about what "first" means here? Does it mean the first element/key was put in the map? Then I am not sure if you could get it from the map through iteration.
Yeah, this was causing tons of repeated records in our production environment, so we have already deployed a version built off this branch to mitigate the issue. |
LGTM |
Hey @jamiees2 This is great! Thanks for this contribution. Also, did you do a double check to make sure no data were lost? |
Yup, the other metrics on the Kinesis end (records ingested) remained the same before and after the rollout |
@zackwine FYI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please squash the commits into one or improve the commit messages
Signed-off-by: James Elias Sigurdarson <jamiees2@gmail.com>
Will include this one in our release this week |
Signed-off-by: James Elias Sigurdarson jamiees2@gmail.com
Description of changes:
The aggregator function has a bug I was wondering about earlier, but recently realized causes actual problems in our setup.
Some notes to provide context:
When producing a record and switching over the aggregator due to size limitations, we start a new aggregation record.
When aggregating into the complete record, we choose
pkeys[0]
to be the partition key of the Kinesis record.The bug is that when we switch over to the new aggregation record, we don't regenerate the partition key. The partition key passed is consistent for the entire aggregation, and after returning, we regenerate this key, but we add the first record to the aggregator with the wrong partition key.
The end result is that the next aggregation record is produced with the same partition key as the previous aggregation record. Funny enough this is only a problem for the first aggregation record produced after the switch over, after which
pkeys[0]
will always never match the remaining records.This is a problem when the first record is right up against the 1MB shard limit, because the next record will guaranteed end up in the same shard as the first record. As a result, we see a
ErrCodeProvisionedThroughputExceededException
, and the chunk can never be submitted.Anyway, this fixes the issue by refactoring the random string generator into a class which can be passed around, and handing control over random string generation to the aggregator itself. This felt like the most maintainable solution, but ends up refactoring the way we manage partition keys. The changes themselves aren't too bad, instead of returning a random string,
getPartitionKey
returns a(partitionKey, ok)
tuple, which is handled differently between the aggregated and non-aggregated impl.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.