Kinesis分区键始终位于同一个分片中

isa*_*zan 4 amazon-kinesis

我有一个带有2个分片的kinesis流,如下所示:

{
    "StreamDescription": {
        "StreamStatus": "ACTIVE",
        "StreamName": "my-stream",
        "Shards": [
            {
                "ShardId": "shardId-000000000001",
                "HashKeyRange": {
                    "EndingHashKey": "17014118346046923173168730371587",
                    "StartingHashKey": "0"
                },
            {
                "ShardId": "shardId-000000000002",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "17014118346046923173168730371588"
                },
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

发送方设置通常为UUID的分区.它总是落在shard-002之上,这使得系统不能进行负载平衡,因此无法扩展.

作为旁注,kinesis使用md5sum分配记录,然后将其发送到包含其范围内的结果哈希的分片.事实上,当我在我使用的UUId上测试它时,它们总是落在同一个碎片中.

echo -n 80f6302fca1e48e590b09af84f3150d3 | md5sum
4527063413b015ade5c01d88595eec11  

17014118346046923173168730371588 < 4527063413b015ade5c01d88595eec11 < 340282366920938463463374607431768211455
Run Code Online (Sandbox Code Playgroud)

关于如何解决这个问题的任何想法?

az3*_*az3 12

首先,请参阅此问答:如何确定AWS kinesis流中的分区键总数?

关于你的情况; 你有2个分片,但它们的哈希键范围不相等.

分区键shard 1包含的数量:

17014118346046923173168730371587 - 0 = 17014118346046923173168730371587

分区键shard 2包含的数量:

340282366920938463463374607431768211455 - 17014118346046923173168730371587 = 340282349906820117416451434263037839868

这两者之间有很大的不同;

17014118346046923173168730371587:17 x 10 ^ 30

340282349906820117416451434263037839868:34 x 10 ^ 37

如果碎片1在"0 - 170141183460469231731687303715884105727"之间并且碎片2在"170141183460469231731687303715884105728 - 340282366920938463463374607431768211455"之间,那将是非常棒的.

您可能使用过台式机或其他低精度计算器.尝试更好的计算器.见下面的例子;

package com.cagricelebi.kinesis.core.utils;

import java.math.BigInteger;

public class MyCalc {

    public static void main(String[] args) {
        try {

            String num1 = "340282366920938463463374607431768211455";
            String num2 = "-17014118346046923173168730371587";

            String diff = bigCalc(num1, num2, "1", "1");
            System.out.println("result1 : " + diff); // 340282349906820117416451434263037839868

            String optimumHalf = bigCalc(num1, "0", "1", "2");
            System.out.println("result2 : " + optimumHalf); // 170141183460469231731687303715884105727

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Basic calculator.
     * First adds up first two elements, than multiplies the summation.
     * The result is the division of the multilication to divisor.
     *
     * @param bigInt A
     * @param bigInt2 B
     * @param multiplicator C
     * @param divisor D
     * @return ((A+B)*C)/D
     */
    private static String bigCalc(String bigInt, String bigInt2, String multiplicator, String divisor) {
        BigInteger summation = new BigInteger(bigInt).add(new BigInteger(bigInt2));
        BigInteger multiplication = summation.multiply(new BigInteger(multiplicator));
        BigInteger division = multiplication.divide(new BigInteger(divisor));
        return division.toString();
    }

}
Run Code Online (Sandbox Code Playgroud)


isa*_*zan 4

经过几个小时的调查,我找到了根本原因,又是人为错误。在这里分享解决方案,即使它很简单,也可以节省其他人可以花在上面的时间。

问题的出现是由于原始流的分割方式造成的。当您将一个流拆分为一个分片时,您必须计算新子分片的起始哈希键。这个新的哈希键通常位于父分片哈希键范围的中间。

新创建的分片(父分片)将具有以下范围:

0 - 340282366920938463463374607431768211455
Run Code Online (Sandbox Code Playgroud)

因此,您天真地转到 Windows 计算器并复制粘贴此“340282366920938463463374607431768211455”,然后将其除以 2。

我忽略并且很容易忽略的问题是,Windows 计算器实际上会在不通知您的情况下截断数字。粘贴到计算器中的上述数字现在将为 "34028236692093846346337460743176" 。一旦你将它除以 2,你实际上会得到一个与父分片的范围相比非常小的数字,然后你的记录将不会被分发,它们将转到获得该范围的较大部分的分片。

一旦您将上面的数字输入适用于大数字的计算器,您将得到该范围的中间值。我用它来计算范围: https: //defuse.ca/big-number-calculator.htm

进行此更改后,记录分布完美,系统可扩展性良好。