Reprint Please specify Source: http://blog.csdn.net/tang9140/article/details/43445511This article mainly describes how to use the Xmemcached client to interact with the memcached server. Through the Xmemcached API call and memcached set/get command comparison and tracking xmemcached source code, so that we have a deeper understanding of the Xmemcached API, to understand how it works from the bottom up, In order to be able to conduct some specific interface closure and optimization work in the project.
Is it called memcache or memcached?
Online there is a saying is: Memcache is the name of this project, and memcached is its server side of the main program file name. I checked the Memcache's official website http://memcached.org/,home page has been quoted is memcached. No matter what the name is appropriate, here is the unified call memcached, only represents my personal habits.
memcached Introduction to the topic, memcached is a distributed high-performance memory-level object caching system, and is open source free projects. All of its key-value data is put in memory, which is one reason for its efficiency, and also means that when the system shuts down, all data is lost. By using memcached caching system, we can reduce the number of dynamic Web database queries, improve the performance of the website, and often act as the WEB2.0 website caching solution. The memcached client provides multiple language API support, such as C + +, Perl, PHP, Java, C #, Ruby, and more.
Memcached's Java client currently has 3
- Memcached Client for Java is more stable, earlier and wider than spymemcached;
- Spymemcached is more efficient than Memcached Client for Java;
- Xmemcached is more effective than spymemcache concurrency;
The use of the first two clients is not detailed here.
Three-part explanation of xmemcached client
- Xmemcached Client Use Demo
- Set/get method Source Tracking
- Compare Memcached's Set/get command
One, xmemcached client use demo I was building a project with Maven, in order to use xmemcached, need to add in Pom.xml
<dependency><groupid>com.googlecode.xmemcached</groupid><artifactid>xmemcached</ Artifactid><version>1.4.3</version></dependency>
Xmemcached Use the sample demo as follows
public static void Main (string[] args) throws IOException { Memcachedclientbuilder builder = new Xmemcachedclientbuil Der (Addrutil.getaddresses ("127.0.0.1:11211")); Memcachedclient memcachedclient = Builder.build (); try { memcachedclient.set ("key", 0, "Hello world!"); String value = Memcachedclient.get ("key"); SYSTEM.OUT.PRINTLN ("Key value:" + value); } catch (Exception e) { e.printstacktrace (); } try { memcachedclient.shutdown (); } catch (IOException e) { e.printstacktrace (); } }
Next, trace the source code of these two methods in detail.
Second, Set/get method source tracking 1.set You can use the debug mode, step by step tracking set and get process, the specific process does not demonstrate, the first direct list of the set method of the approximate source code call process is as follows (the middle may omit some method calls)
Xmemcachedclient.set () Xmemcachedclient.sendcommand () memcachedconnector.send () abstractsession.write () memcachedtcpsession.wrapmessage () Textstorecommand.encode () textstorecommand.encodevalue () Serializingtranscoder.encode ( ) Baseserializingtranscoder.serialize ()
First call the Xmemcacheclient.set (final string key, Final int exp, final Object value) method, the key parameter corresponds to the string "key", and the exp parameter corresponds to the integer 0 (the expression cache never expires). The value parameter corresponds to the string "Hello world!". After a series of method calls, the final call to the Serializingtranscoder.encode (Object O) method, at which time the parameter o receives the argument value is the set string "Hello world!", the method body code is as follows:
Public final Cacheddata encode (Object o) {byte[] b = null;int flags = 0;if (o instanceof String) {b = encodestring (string ) o);} else if (o instanceof Long) {if (this.primitiveasstring) {b = encodestring (o.tostring ());} else {b = this.transcoderutils. Encodelong ((Long) o);} Flags |= Special_long;} else if (o instanceof Integer) {if (this.primitiveasstring) {b = encodestring (o.tostring ());} else {b = This.transcoderuti Ls.encodeint ((Integer) o);} Flags |= Special_int;} else if (o instanceof Boolean) {if (this.primitiveasstring) {b = encodestring (o.tostring ());} else {b = This.transcoderuti Ls.encodeboolean ((Boolean) o);} Flags |= Special_boolean;} else if (o instanceof date) {b = This.transcoderUtils.encodeLong ((Date) O). GetTime ()); Flags |= special_date;} else if (o Instanceof Byte) {if (this.primitiveasstring) {b = encodestring (o.tostring ());} else {b = This.transcoderUtils.encodeByte ((Byte) o);} Flags |= Special_byte;} else if (o instanceof Float) {if (this.primitiveasstring) {b = encodestrING (o.tostring ());} else {b = This.transcoderUtils.encodeInt (Float.floattorawintbits ((Float) o));} Flags |= special_float;} else if (o instanceof Double) {if (this.primitiveasstring) {b = encodestring (o.tostring ());} else {b = this.transcoderutil S.encodelong (Double.doubletorawlongbits ((Double) o)); Flags |= special_double;} else if (o instanceof byte[]) {b = (byte[]) o;flags |= Special_bytearray;} else {b = serialize (o); flags |= Serialized;} Assert b! = null;if (this.primitiveasstring) {//It is not being serialized,so change it to string Typeif (Flags & Seria lized) = = 0) {flags = 0;}} if (B.length > This.compressionthreshold) {byte[] compressed = compress (b); if (Compressed.length < b.length) {if (lo G.isdebugenabled ()) {Log.debug ("compressed" + O.getclass (). GetName () + "from" + B.length + "to" + Compressed.length);} b = compressed;flags |= compressed;} else {if (log.isdebugenabled ()) {Log.debug ("Compression increased the size of" + O.getclass (). GetName () + "from" + B.len gth+"to" + Compressed.length);}}} return new Cacheddata (flags, B, this.maxsize,-1);}
First it declares the local variable B (used to store the byte array that needs to be put into the memcached server) and flags (used to store the flag information). It then determines whether the object o is a string type, a long integer type, etc., and encodes the object o into the corresponding byte array to be stored in the local variable B.
Pay particular attention to line 57th, when the type of O is not a string, the wrapper type of the base type, and the byte[] array, the Baseserializingtranscoder.serialize () method is called, and the source code of the method is as follows:
Protected byte[] Serialize (Object o) {if (o = = null) {throw new NullPointerException ("Can ' t serialize null");} byte[] RV = null;try {bytearrayoutputstream bos = new Bytearrayoutputstream (); ObjectOutputStream os = new Objectoutputstre AM (BOS); Os.writeobject (o); Os.close (); Bos.close (); rv = Bos.tobytearray ();} catch (IOException e) {throw new IllegalArgumentException ("Non-serializable object", e);} return RV;}
Obviously, the method is to serialize the object, convert the Java object into a byte array, and return. Believe that you see here, you should understand why the custom object needs to implement the serializable interface to be saved into the memcached . If the data object does not implement the Serializable interface, then when the object is serialized, the IOException is thrown, eventually illegalargumentexception is thrown, and the Non-serializable object is prompted.
Another highlight is the role of the Cacheddata class, which encapsulates the CAS value, which is used to implement atomic updates, that is, each time a client makes an update request, the CAS value is included in the request information, and the memcached server receives the request. Compares the CAS value to the CAS value of the data stored in the server, overwriting the old data with new data, if it is equal, or the update fails. Especially useful in concurrent environments), data (that is, data values to be cached or cached data obtained in byte[] array), flag information (identifying byte[] Array additional data type information and byte[] array is compressed, etc. stored with an int type) and other information.
Set source analysis Here, the following is the get source code.
2.get
In the same way, the approximate source code call procedure for the Get method is listed as follows:
Xmemcachedclient.get () xmemcachedclient.fetch0 () Xmemcachedclient.sendcommand () memcachedconnector.send () abstractsession.write () memcachedtcpsession.wrapmessage () Textgetcommand.encode ( ) Serializingtranscoder.decode () serializingtranscoder.decode0 () baseserializingtranscoder.deserialize ()
First, the Xmemcacheclient.get (final string key) method is called, and the key parameter corresponds to the string "key". From this method until the Textgetcommand.encode () call, can be seen as the assembly of the get command and sent to the server process, after receiving the server response message, the response message is assembled into Cacheddata, and call the Serializingtranscoder.decode (Cacheddata D) method, that is, the byte stream decoding work. The method code is as follows:
Public final Object Decode (Cacheddata D) {byte[] data = D.getdata (); int flags = D.getflag (); if (Flags & compressed)! = 0) {data = Decompress (D.getdata ());} Flags = Flags & Special_mask;return decode0 (d,data, flags);}
First gets the byte array and the flag information, depending on the flag bit to determine whether to extract the byte array. Finally call DECODE0 (Cacheddata cacheddata,byte[] data, int flags) method, the code is as follows:
Protected Final Object Decode0 (cacheddata cacheddata,byte[] data, int flags) {Object RV = Null;if ((Cacheddata.getflag () & Amp serialized)! = 0 && Data! = null) {RV = deserialize (data);} else {if (this.primitiveasstring) {if (flags = = 0) {RE Turn decodestring (data);}} if (Flags! = 0 && Data! = NULL) {switch (flags) {Case SPECIAL_BOOLEAN:RV = boolean.valueof (this.transcoderUtils.de Codeboolean (data)); Break;case special_int:rv = integer.valueof (this.transcoderUtils.decodeInt (data)); break;case SPECIAL_LONG:RV = long.valueof (This.transcoderUtils.decodeLong (data)) Break;case SPECIAL_BYTE:RV = byte.valueof ( This.transcoderUtils.decodeByte (data)) Break;case SPECIAL_FLOAT:RV = new FLOAT (Float.intbitstofloat ( THIS.TRANSCODERUTILS.DECODEINT (data)); Break;case special_double:rv = new DOUBLE (double.longbitstodouble ( This.transcoderUtils.decodeLong (data)), break;case special_date:rv = new DATE (This.transcoderUtils.decodeLong (data )); Break;case special_bytearray:rv = Data;break;default:log.Warn (String.Format ("Undecodeable with flags%x", Flags));}} else {RV = decodestring (data);}} return RV;}
The above method is actually the inverse implementation of the encode (object o) method, converting the byte array into an object. Note that line 4th calls the deserialize (byte[] in) method, which has the following code (omitting the catch, the finally part):
Protected object Deserialize (byte[] in) {object RV = null; Bytearrayinputstream bis = Null;objectinputstream is = null;try {if (in! = null) {bis = new bytearrayinputstream (in); is = new ObjectInputStream (bis) { @Override protected class<?> resolveclass (ObjectStreamClass desc) Throws IOException, ClassNotFoundException { try { //when class is not found,try to load it from context class Loa Der. return Super.resolveclass (DESC); } catch (ClassNotFoundException e) { return Thread.CurrentThread (). Getcontextclassloader (). LoadClass ( Desc.getname ());}} ; RV = Is.readobject ();}} ... return RV;}
The code above is the deserialization of the object and returns. Each deserialization operation gets anew Objects, any action on the new object does not affect the value stored in the memcached. Iii. comparison of Memcached's set/get commands
In addition to the above interactions with memcached through Java code, we can also interact directly with them by means of commands. The steps are as follows:
1. Open the cmd window first
2. Connect the memcached server via telnet with the following command:
Telnet 127.0.0.1 11211
3. If the connection is successful, you can directly enter the command to interact with the memcached server.
1. Storing commands
The format is as follows
<command name> <key> <flags> <exptime> <bytes><data block>
The parameters are described as follows:
<command name> set/add/replace
<key> Find keywords
<flags> clients use it to store extra information about key-value pairs
<exptime> Survival time of this data, 0 means forever
<bytes> number of bytes stored
<data block> stored data block (can be directly understood as value in the key-value structure)
Special instructions for each storage command:
- The SET command adds an operation when the key does not exist, otherwise it is updated.
- The add command cannot be added if key does not exist
- Replace command can be replaced if key exists
Example Demo:
Set myname 0 0 9super manstored
2. Read commands
Get key [Key1] ...
Gets one or more key values, separated by a space between the keys.
Example Demo:
Get mynamevalue myname 0 9super manend
In addition to the above-mentioned commands, there are get, CAs, stats and other orders, we are interested to learn.
3. Analogy
Analogy under xmemcached client use, it is not difficult to find interesting places:
The set command <key> and <exptime> correspond to Xmemcacheclient.set (final String key, Final int exp, final Object value) The key and exp parameters in the method. The <flags> and <data block> correspond to the flag and data member variables of the Cacheddata package class.
The Get command <key> corresponds to the key parameter to the Xmemcacheclient.get (final String key) method, and the return result of the GET command corresponds to Serializingtranscoder.decode ( Cacheddata d) The type of the parameter d,d of the method is Cacheddata, which encapsulates the flag and data information.
From the above comparison, it is not difficult to find that both the memcached command or the xmemcached client is just a memcached client implementation, they adhere to the same request and Response message specification. At a lower level, both of these approaches are done by establishing a TCP connection and then sending a request message that conforms to the Memcached convention, and after receiving the Memcached server reply message, It is also decoded according to the memcached reply message contract (The xmemcached client takes advantage of the flag field implementation to convert the data byte array into the type required by the application layer).
In other words: the memcached cache system provides the server-side implementation (C language) and contracts the message format that the client communicates with the servers, more precisely the byte-stream format (communicating over TCP). Different language clients are just implementations of this specification. Of course memcached has provided client implementations for most languages, but you can also develop a client implementation yourself.
Iv. How to optimize xmemcached client code, improve efficiency
From the previous source analysis can be seen, if the memcached is stored in the Bean object, you need to implement the serializable interface to support the Java object serialization. As far as I know, Java comes with serialization of objects, not only time-consuming serialization and deserialization operations, but also a larger array of bytes. Therefore, we can consider a new codec technology, I recommend the use of Fastjson, which is not only efficient, and the resulting JSON string volume is small. Other optimization measures, if any, to add
Java xmemcached Use and source code detailed