心有多大舞臺便有多大

          Embrace changes, pursue excellence, share niceness.

          hessian序列化協議+memcached的緩存存取

          大名鼎鼎的memcached恐怕沒人不知道吧!hessian是一種遠程調用的機制,類似與web service,不過它是使用自己的序列化協議.
          那么,為什么要把hessian的序列化協議和memcached結合起來實現緩存的讀取呢?
          有過使用memcached的經驗的人會了解到,php+memcached的性能是最好的,java+memcached的性能比較差,其主要原因就是在于java本身的序列化機制很慢.
          我做了個簡單的測試,一個UserData類,有一個字符串屬性,一個日期屬性,一個double屬性,分別用java,hessian來序列化一百萬次,結果讓人吃驚,不止是hessian序列化的速度要比java的快上一倍,而且hessian序列化后的字節數也要比java的少一倍.因為我在測試的時候只是做了序列化這部分的工作,并沒有把序列化后的結果放到網絡上傳輸,所以,實際中的性能hessian應該會更好!
          既然hessian的序列化協議要比java本身的好,而memcached客戶端的性能又在很大程度上依賴與對象的序列化.所以,我就決定把我的cache實現中序列化這部分的工作改成用hessian來實現了.
          我用的memcached客戶端是用的danga.MemCached包,主要是改動了MemCachedClient的get方法及set方法,在set方法中改為調用hessian的序列化:
          ByteArrayOutputStream bos = new ByteArrayOutputStream();
          //修改以前的序列化代碼:
           //(new ObjectOutputStream( bos )).writeObject( value );
          //修改后的序列化代碼:
          serializeByHessian(bos, value);
           val = bos.toByteArray();
          serializeByHessian方法如下:

           protected void serializeByHessian(OutputStream os, Object object) throws IOException {
                  AbstractHessianOutput out = new Hessian2Output(os);;
                  SerializerFactory serializerFactory = getSerializerFactory();
                  out.setSerializerFactory(serializerFactory);
                  out.startReply();
                  out.writeObject(object);     
                  out.completeReply();
                  out.flush();
           }
          在get方法中主要是修改了這個方法調用的類ContextObjectInputStream的readObject方法:
          在ContextObjectInputStream中覆蓋了readObjectOverride方法:
           protected Object readObjectOverride() throws IOException,  ClassNotFoundException {
                  ByteArrayInputStream is = new ByteArrayInputStream(bytes);
                  ClHessian2Input in = new ClHessian2Input(is, this.mLoader);
                  in.setSerializerFactory(getSerializerFactory());
                  int code = in.read();//"r"
                  int major = in.read();//>=2
                  int minor = in.read();//0
                  Object value = in.readObject();
                  is.close();
                  return value;
           }
          因為我的框架是基于osgi的,所以我重載了Hessian2Input,把classloader作為參數傳進去,否則hessian在反序列化的時候會找不到類.如果你沒有用osgi框架的話, ClHessian2Input in = new ClHessian2Input(is, this.mLoader);這行代碼就可以直接用: Hessian2Input in = new Hessian2Input(is);
          這樣修改就基本完成了.
          我把memcached client的序列化協議改為hessian也有另外一個系統架構的原因,那就是因為我的服務層邏輯都是用java+spring+osgi的方式實現,而web層則是用php實現,兩者之間通訊已經是采用hessian的遠程調用.所以,部分緩存數據在服務層通過java設置到memcached服務器中,在php中一樣可以用memcached php client讀取出來.(php的memcached client我用的是memcached-client.php,而不是php擴展,所以一樣可以修改memcached-client.php的序列化機制)


          posted on 2008-06-18 10:04 pony 閱讀(7877) 評論(11)  編輯  收藏 所屬分類: Java

          評論

          # re: hessian序列化協議+memcached的緩存存取 2008-06-18 10:17 pony

          另外附帶說一句,我的經驗,在使用memcached的時候,客戶端在創建socket連接時最好把nagle設置為false.熟悉tcp協議的都知道setTcpNoDelay有什么作用.如果Tcp_NoDelay被設置為true,那么發送數據包時將使用nagle算法對要發送的數據進行緩存處理,只有當達到一定數量之后才把包發送出去,設置為false則立即發送包.對于memcached緩存,一般我們放進去的數據,以及發送的get命令都是很小的包,為了將數據及時傳輸出去,所以要禁用nagle.  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取 2008-06-18 10:35 CHINA BAIDU

          不錯1!  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取 2008-06-18 12:19 dennis

          @pony
          很好的帖子,不知道換成了hession有沒有測試數據?
          對于setTcpNoDelay說反了吧?setTcpNoDelay為true,就是設置TCP_NODELAY,也就是禁掉Nagle算法;默認就是false,表示啟用Nagle算法。禁掉Nagle算法可以提高響應性,相應地會降低吞吐量,在這個場景中沒啥必要。



            回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取 2008-06-18 13:24 lizongbo

          hession 的序列化效率確實不錯,

          不過需要序列化的對象,試過實現java.io.Externalizable接口的方式沒?


            回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取 2008-06-18 13:41 pony

          @dennis
          測試hessian和java序列化的代碼,寫的不好請見諒^_^
          由于把數據存儲到memcached服務器中跟網絡環境,內存有很大關系,跟memcached client設置的參數也有很大關系,所以就不做memcached的存取測試了.

          下面的代碼在我的機器上的結果是:
          serialize 1000000 users with hessian spend 8 seconds, total size:93000000
          serialize 1000000 users with java spend 17 seconds, total size:190000000

          /**
          * Created at 2008-06-13.
          * 測試比較java和hessian的序列化效率.
          */
          import java.io.ByteArrayOutputStream;
          import java.io.ObjectOutputStream;
          import java.io.Serializable;
          import java.util.Date;

          import com.caucho.hessian.io.AbstractHessianOutput;
          import com.caucho.hessian.io.Hessian2Output;
          import com.caucho.hessian.io.SerializerFactory;

          /**
          * @author pony
          *
          * 如果有任何對代碼的修改,請按下面的格式注明修改的內容.
          * 序號 時間 作者 修改內容
          * 1. 2008-6-13 pony created this class.
          */
          public class TestSerializerPerformanceFucntion {
          //序列化次數.
          private static final int COUNT = 1000000;

          private SerializerFactory factory;

          public static void main(String[] args) throws Exception {
          new TestSerializerPerformanceFucntion().testHessianSerializer();
          new TestSerializerPerformanceFucntion().testJavaSerializer();
          }

          public void testHessianSerializer() throws Exception {
          long curr = new Date().getTime();
          int size = COUNT;
          int len = 0;
          for (int i=0; i<size; i++) {
          User user = new User();
          ByteArrayOutputStream os = new ByteArrayOutputStream();
          AbstractHessianOutput out = new Hessian2Output(os);;
          SerializerFactory serializerFactory = getSerializerFactory();
          out.setSerializerFactory(serializerFactory);
          out.startReply();
          out.writeObject(user);
          out.completeReply();
          out.flush();
          os.flush();
          len += os.size();
          out.close();
          }
          long now = new Date().getTime();
          System.out.println("serialize " + size + " users with hessian spend " + (now-curr)/1000 + " seconds, total size:" + len);
          }

          public void testJavaSerializer() throws Exception {
          long curr = new Date().getTime();
          int size = COUNT;
          int len = 0;
          for (int i=0; i<size; i++) {
          User user = new User();
          ByteArrayOutputStream os = new ByteArrayOutputStream();
          new ObjectOutputStream(os).writeObject(user);
          os.flush();
          len += os.size();
          os.close();
          }
          long now = new Date().getTime();
          System.out.println("serialize " + size + " users with java spend " + (now-curr)/1000 + " seconds, total size:" + len);
          }

          public SerializerFactory getSerializerFactory() {
          if (null == factory) {
          factory = new SerializerFactory();
          }
          return factory;
          }
          }


          class User implements Serializable {
          /**
          * serial Version UID.
          */
          private static final long serialVersionUID = -4845300297590675952L;

          private String name = "test name";

          private Date birthday = new Date();

          private int age = 10;

          private double money = 1000.56;

          /**
          * @return the name
          */
          public String getName() {
          return name;
          }

          /**
          * @param name the name to set
          */
          public void setName(String name) {
          this.name = name;
          }

          /**
          * @return the birthday
          */
          public Date getBirthday() {
          return birthday;
          }

          /**
          * @param birthday the birthday to set
          */
          public void setBirthday(Date birthday) {
          this.birthday = birthday;
          }

          /**
          * @return the age
          */
          public int getAge() {
          return age;
          }

          /**
          * @param age the age to set
          */
          public void setAge(int age) {
          this.age = age;
          }

          /**
          * @return the money
          */
          public double getMoney() {
          return money;
          }

          /**
          * @param money the money to set
          */
          public void setMoney(double money) {
          this.money = money;
          }

          /**
          * @return the serialVersionUID
          */
          public static long getSerialVersionUID() {
          return serialVersionUID;
          }
          }  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取 2008-06-18 13:54 pony

          @lizongbo
          謝謝!這是個好建議!試過之后,只有驚訝!結果是比hessian的還快了!
          運行結果是:
          serialize 1000000 users with hessian spend 10 seconds, total size:93000000
          serialize 1000000 users with java spend 9 seconds, total size:86000000

          把上面代碼中的Serializable 改為
          Externalizable,實現下面兩個方法:
          public void readExternal(ObjectInput in) throws IOException,
          ClassNotFoundException {
          String name = in.readUTF();
          long time = in.readLong();
          int age = in.readInt();
          double money = in.readDouble();
          this.setName(name);
          this.setBirthday(new Date(time));
          this.setAge(age);
          this.setMoney(money);
          }

          public void writeExternal(ObjectOutput out) throws IOException {
          out.writeUTF(name);
          out.writeLong(birthday.getTime());
          out.writeInt(age);
          out.writeDouble(money);
          }

          不過因為從架構上考慮,我要用php來讀取cache中的內容,所以我希望序列化后的對象能遵循一個統一的協議,所以,我暫時還是要用hessian的方式.  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取 2008-12-04 10:31 LiMengyan

          博主能否來個hessian序集?講講hessian部署的結構?我想看看hessian這個服務模塊是怎么給其他應用提供服務的?  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取 2010-09-20 11:00 thebye85

          @pony
          怎么我這邊測試還是hessian快  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取[未登錄] 2010-10-05 16:38 Jeff

          好文章!  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取[未登錄] 2011-06-24 12:03 HK

          好文啊!  回復  更多評論   

          # re: hessian序列化協議+memcached的緩存存取[未登錄] 2013-12-19 15:40 sa

          hessian4.0.7有一個bigdecimal序列化的bug  回復  更多評論   

          主站蜘蛛池模板: 卓尼县| 海安县| 额尔古纳市| 南昌市| 临邑县| 金山区| 论坛| 峡江县| 禄丰县| 宣武区| 阜宁县| 新乡县| 阳东县| 西畴县| 大厂| 天气| 沿河| 夏津县| 台州市| 沂南县| 临武县| 台安县| 榆社县| 南华县| 海丰县| 肥城市| 额尔古纳市| 苗栗县| 灵山县| 太仓市| 崇州市| 沙洋县| 新乐市| 新干县| 贺兰县| 扎兰屯市| 保靖县| 江孜县| 鄯善县| 镇安县| 藁城市|