First, analyze some code when the Java client is started.
Memcached allows you to directly set multiple servers attributes to achieve multiple memcahced balancing. The corresponding attribute is weights, which literally means weight. After analyzing the code, it is the same as what I think.
The code for starting memcached is usually as follows:
Java code
- Sockiopool pool = sockiopool. getinstance (poolname );
- Pool. setservers (servers );
- Pool. setweights (weights );
- Pool. setinitconn (initconn );
- Pool. setminconn (minconn );
- Pool. setmaxconn (maxconn );
- Pool. setmaxidle (maxidle );
- Pool. setmaxbusytime (maxbusytime );
- Pool. setmaintsleep (maintsleep );
- Pool. setsocketto (socketto );
- Pool. setsocketconnectto (socketconnectto );
- Pool. setnagle (Nagle );
- Pool. sethashingalg (sockiopool. new_compat_hash );
- Pool. initialize ();
- Memcachedclient client = new memcachedclient (poolname );
Both servers and weights are an array, that is, multiple servers can be set at the same time.
Then let's take a look at what Java code pool. initialize () has done.
- Availpool = new hashmap <string, Map <sockio, long> (servers. length * initconn );
- Busypool = new hashmap <string, Map <sockio, long> (servers. length * initconn );
- Deadpool = new identityhashmap <sockio, integer> ();
- Hostdeaddur = new hashmap <string, long> ();
- Hostdead = new hashmap <string, date> ();
- Maxcreate = (poolmultiplier> minconn )? Minconn: minconn/poolmultiplier; // only create up to maxcreate connections at once
- If (log. isdebugenabled ()){
- Log. debug ("++ initializing pool with following settings :");
- Log. debug ("++ initial size:" + initconn );
- Log. debug ("++ + min spare:" + minconn );
- Log. debug ("++ + Max spare:" + maxconn );
- }
- // If servers is not set, or it empty, then
- // Throw a runtime exception
- If (servers = NULL | servers. Length <= 0 ){
- Log. Error ("+++ trying to initialize with no servers ");
- Throw new illegalstateexception ("++ trying to initialize with no servers ");
- }
- // Initalize our internal hashing Structures
- If (this. hashingalg = consistent_hash)
- Populateconsistentbuckets ();
- Else
- Populatebuckets ();
We can see that this is to open up some connection pool space, and then call the algorithm to execute populatebuckets () based on the hash algorithm we selected, or populateconsistentbuckets ();
The hash algorithm has four types of Java code.
- // Native string. hashcode ();
- Public static final int native_hash = 0;
- // Original compatibility hashing algorithm (works with other clients)
- Public static final int old_compat_hash = 1;
- // New CRC32 based compatibility hashing algorithm (works with other clients)
- Public static final int new_compat_hash = 2;
- // MD5 based -- stops thrashing when a server added or removed
- Public static final int consistent_hash = 3;
We usually use new_compat_hash, which ensures that wokrs with other clients
So let's take a look at what populatebuckets () has done.
Java code
- This. Buckets = new arraylist <string> ();
- For (INT I = 0; I <servers. length; I ++ ){
- If (this. weights! = NULL & this. Weights. length> I ){
- For (int K = 0; k <this. weights [I]. intvalue (); k ++ ){
- This. Buckets. Add (servers [I]);
- If (log. isdebugenabled ())
- Log. debug ("++ added" + servers [I] + "to server bucket ");
- }
- }
- Else {
- This. Buckets. Add (servers [I]);
- }
- // Create initial connections
- For (Int J = 0; j <initconn; j ++ ){
- Sockio socket = createsocket (servers [I]);
- If (socket = NULL ){
- Break;
- }
- Addsockettopool (availpool, servers [I], socket );
- }
- }
Assume that the servers we set are 192.168.0.1: 44444 and 192.168.0.2: 22222.
Then we set weights to 5 and 3.
The value of the buckets list will eventually be
[
192.168.0.1: 44444,
192.168.0.1: 44444,
192.168.0.1: 44444,
192.168.0.1: 44444,
192.168.0.1: 44444,
192.168.0.2: 22222,
192.168.0.2: 22222.
192.168.0.2: 22222.
]
Then, the socket is created by Servers Based on the initcon initial connections.
So what is the purpose of this buckets?
It is called when we use set to store objects.
Java code
- Sockiopool. sockio sock = pool. getsock (Key, hashcode );
Let's take a look at the pool. getsock code.
Java code
- // Get initial Bucket
- Long bucket = getbucket (Key, hashcode );
- String Server = (this. hashingalg = consistent_hash)
- ? Consistentbuckets. Get (bucket)
- : Buckets. Get (INT) bucket );
Here is a code segment. Let's look at the Java code of getbucket.
- Private long getbucket (string key, integer hashcode ){
- Long Hc = gethash (Key, hashcode );
- If (this. hashingalg = consistent_hash ){
- Return findpointfor (HC );
- }
- Else {
- Long bucket = HC % buckets. Size ();
- If (bucket <0) bucket * =-1;
- Return bucket;
- }
- }
Regardless of the key and hashcode, we can see that after a HC value is calculated, HC % buckets is directly implemented. size () is actually based on the number of buckets, the final value must be buckets. A value in the size () range.
Then the final server value is based on buckets. get (INT) bucket), then if we get the bucket is 3, we will get the list by referring to the value in the buckets above. get (3) = 192.168.0.1: 44444, so different servers are obtained based on the values set by weight. If weights is set to 10:1, 10 identical servers and 10 different servers are obtained in buckets, in the future, the server hash is likely to be the first server set in servers.
Address: http://bachmozart.javaeye.com/blog/211836