So, I was hoping to write a little snippet of code to embed on my blog to allow people to get the token ranges for load balancing their cluster.
In Cassandra, when using the random partitioner, all keys are given a token (essentially an md5 of the Key) that is between 0 and 2^127 (0 through 170141183460469231731687303715884105728 for non-nerds). That range is known as the ring.
Each member node of the Cassandra cluster owns a range of those keys on the ring in the same vein you’d divide up a pie.
Now, if you had a pie and you knew you had 4 people who were going to share it, you’d split it into four pieces. In terms of 4-node Cassandra cluster node-balancing you’d want to give each node a quarter of the ring.
Simple bit of math to do, but Javascript decided it didn’t want to play ball and handle integers as big as 2^127.
Drama.
My Brother-in-Law, to mock me, wrote it quickly in php, which I’ll post here shortly. (He is moving to San Francisco soon, hot software dev shops looking for people, note this!)
UPDATE: Buddy’s Epic Cassandra Token Calculator is here.
I’m not a programmer so my opinion is meaningless in these matters, and am generally a ‘right tool for the right job’ kinda guy but… well.. really, Java?
Python Code:
5 lines mostly cribbed from Apache’s wiki, scriptified by me.
#!/usr/bin/env python
import sys
nodes = int(sys.argv[1])
for x in xrange(nodes):
print "Node", x, "initial_token:", 2 ** 127 / nodes * x
Results:
nathan@bebop ~ $ ./CassandraRingCalc.py 5
Node 0 initial_token: 0
Node 1 initial_token: 34028236692093846346337460743176821145
Node 2 initial_token: 68056473384187692692674921486353642290
Node 3 initial_token: 102084710076281539039012382229530463435
Node 4 initial_token: 136112946768375385385349842972707284580
Java Code:
25 lines, further bloated by my inexperience with Java. I imagine a pro would be able to knock it down to 18-20…
UPDATE: Ed Capriolo did it in 17, see comments
import java.io.*;
import java.math.BigInteger;
public class CassandraRingCalc {
public static void main (String[] args) {
String input = null;
int numNodes = 0;
double initToken = 0;
try {
System.out.print("Number of Cassandra Nodes: ");
BufferedReader is = new BufferedReader(
new InputStreamReader(System.in));
input = is.readLine();
numNodes = Integer.parseInt(input);
} catch (NumberFormatException ex) {
System.err.println("Not a valid number: " + input);
} catch (IOException e) {
System.err.println("Unexpected IO ERROR: " + e);
}
BigInteger tok = new BigInteger("170141183460469231731687303715884105728");
for(int i=0; i<numNodes; i++){
System.out.println("Node: " + i);
System.out.println("initial_token: " + tok.multiply(BigInteger.valueOf(i)).divide(BigInteger.valueOf(numNodes)));
}
}
}
Results:
nathan@bebop ~ $ java CassandraRingCalc
Number of Cassandra Nodes: 5
Node: 0
initial_token: 0
Node: 1
initial_token: 34028236692093846346337460743176821145
Node: 2
initial_token: 68056473384187692692674921486353642291
Node: 3
initial_token: 102084710076281539039012382229530463436
Node: 4
initial_token: 136112946768375385385349842972707284582
I’m sure you could do it in negative 4 lines of Perl.. but you probably couldn’t read it.
EVEN if you refactored it to 20 lines and added comments you probably still couldn’t read it.
As for Ruby, I’m not really into Pokémon.
