Fastjson技術

9346 ワード

JSONプロトコルの使用が便利で、ますます人気があります.JSONのプロセッサが多いですが、なぜもう一つ書く必要がありますか?私達は性能の良いJSON Paserが必要ですので、JSON Paserの性能はバイナリプロトコルのように良いです.例えばプロトbufと同じです.これは容易ではないですが、確実にできました.原理的には不可能だと考えている人もいますが、コンピュータは実践科学であり、実際の結果を見ると原理的な導出よりも重要です.
この文章はみんなに教えます.
  • Fastjsonはどれぐらい速いですか?
  • どうしてFastjsonはこんなに速いですか?
  • Fastjsonで何ができますか?
  • はどうやってfastjsonを獲得しますか?
  • 1、まず、Fastjsonはどれぐらい早いですか?
    使ってみます.https://github.com/eishay/jvm-serializers/提供されたプログラムをテストした結果:
     
    プログレッシブ時間
    アンチプログレッシブ時間
    サイズ
    圧縮後のサイズ
    javaプロローグ
    8654
    43787
    889
    541
    hessian
    6725
    10640
    501
    313
    protobuf
    2964
    1745
    239
    149
    thrift
    3177
    1949
    349
    197
    avロ
    3520
    1948
    221
    133
    Json-lib
    45788
    149741
    485
    263
    ジャックソン
    3052
    4161
    503
    271
    fastjson
    2595
    1472
    468
    251
    テストデータ:https://github.com/eishay/jvm-serializers/wiki/TestValue
    これは468 bytesのJSON Bytesテストです.テスト結果から見ると、プロトブンスとアンチプロトブ化にかかわらず、Fastjsonはプロトbufを超えています.それはjava deserializeより30倍以上速くて、json-libより100倍速いです.Fastjsonの存在により、jsonの統一プロトコルを安心して使用できます.テキストプロトコルのメンテナンス性、バイナリプロトコルの性能を実現できます.
    2、なぜFastjsonはこんなに早くできますか?
    JSON処理は主に二つの部分、serializeとdeseserializeを含む.serializeとは、JavaオブジェクトをJSON StringまたはJSON Bytesに変更することです.DeserializeはJSON StringまたはJson Bytesをjavaオブジェクトにします.実はこの過程の中にはJSONライブラリが三つの部分に分かれています.json string<->json tree<->java oject.Fastjsonもこのような変換方式をサポートしていますが、この変換方式は余分なステップがありますので、性能が良くないので、使うことを勧められません.
    一、FastjsonにおけるSerialzieの最適化実現
    1、独自にStringBuiderのようなツール類SerializerWriterを作成する.
    javaオブジェクトをjsonテキストに順番に並べて、文字列を使って直接つなぎ合わせることは不可能です.これは性能が悪いからです.文字列のつなぎ合わせよりもっと良い方法はjava.lang.StringBuiderを使うことです.StringBuiderは速度がとてもいいですが、さらに性能を向上させることができます.fastjsonではStringBuiderのような種類のcomple.aliba.fastjson.serializer.Serializerを提供しています.
    SerializerWriterはいくつかのターゲットとなる方法を提供して、配列の境界線検査を減らします.例えば、public void writeIntAndChar(inti、char c){}のような方法では一度に二つの値をbufに書いて、一回の越境検査を減らすことができる.現在SerializerWriterはまだいくつかの重要な方法があります.越境検査を減らすことができます.まだ実現していません.つまり、実現すれば、serializeの性能をさらに向上させることができます.
    2、ThreadLocalを使ってbufをキャッシュする.
    この方法は対象割当とgcを低減して性能を向上させることができる.SerializerWriterにはchar[]bufが含まれています.逐次列化するごとに一回の割り当てをして、ThreadLocalを使って最適化して、性能を向上させます.
    3、asmを使って反射を避ける
    java beanの属性値を取得するには、反射を呼び出す必要があり、fastjsonは、反射によるオーバーヘッドを回避するためにasmを導入する.fastjsonに内蔵されているasmはobject web asm 3.3.1に基づいて改造されています.必要な部分だけ残して、fastjson asmの部分は1000行以下のコードです.asmを導入して、大きさが大きくなりすぎないようにします.
    4、特殊なIdentityHashMapを使って性能を最適化します.
    fastjsonは各タイプに対してserializerを使用しているので、class->JavaBenSerizierのマッピングがあります.fastjsonはHashMapではなくIdentityHashMapを使用して、equals操作を回避します.HashMapのアルゴリズムのtransfer操作は、同時に死のサイクルを引き起こす可能性があることを知っていますが、ConcerenthashMapはhashMapシリーズより遅くなります.volatileとlockを使用しています.fastjsonは自分で特別なIdentityHashMapを実現して、transferの操作のIdentityHashMapを取り除いて、合併の時に働くことができて、しかし死亡の循環を招くことはできません.
    5、デフォルトはsort field出力を有効にします.
    jsonのobjectはkey/value構造で、正常なhashmapは無秩序で、fastjsonはデフォルトで並べ替えて出力したので、これはdeserialize最適化のために準備します.
    6、jdkを統合して実現するいくつかの最適化アルゴリズム
    fastjsonを最適化する過程で、jdk内部実装のアルゴリズム、例えばint to char[]アルゴリズムなどを参照した.
    二、fastjsonのdeserializerの主な最適化アルゴリズム
    deserializerはparserまたはdecoderとも言われています.fastjsonはこの方面で投入した最適化精力が一番多いです.
    1、tokenを読み出して予測に基づく.
    すべてのパーサーは基本的に品詞処理が必要です.Jsonも例外ではありません.fastjsonの品詞処理には、予測に基づく最適化アルゴリズムが使われています.たとえばkeyの後、一番大きなのはコロンの可能性があります.」「valueの後に、カンマが二つあるかもしれません.」または右括弧があります.」comp.aliba.fastjson.parser.JSONS cannerでは、このような方法が提供されている.
    public void nextToken(int expect) {
        for (;;) {
            switch (expect) {
                case JSONToken.COMMA: //
                    if (ch == ',') {
                        token = JSONToken.COMMA;
                        ch = buf[++bp];
                        return;
                    }
    
                    if (ch == '}') {
                        token = JSONToken.RBRACE;
                        ch = buf[++bp];
                        return;
                    }
    
                    if (ch == ']') {
                        token = JSONToken.RBRACKET;
                        ch = buf[++bp];
                        return;
                    }
    
                    if (ch == EOI) {
                        token = JSONToken.EOF;
                        return;
                    }
                    break;
            // ... ...
        }
    }
    上から切り取ったコードは、予測に基づいてより少ない処理ができるとtokenに読み込まれます.
    2、sort field fast matchアルゴリズム
    fastjsonのserializeはkeyの順に行うので、fastjsonがdeserializerを作る時に、key/valueの内容が規則的であると仮定する最適化アルゴリズムを採用します.この最適化によって、fastjsonはjsonテキストを処理する時、50%以上のtokenを少な目に読み取らせます.これは非常に重要な最適化アルゴリズムです.このアルゴリズムに基づいて,asmを用いて実現し,300%を超える性能向上が明らかになった.
    { "id" : 123, "name" : "   ", "salary" : 56789.79}
      ------      --------          ----------
    上記の例では、点線で表示されている3つの部分がキーであり、キーであればid、key_name、key_salaryという三つのkeyは順番です.最適化処理ができます.この三つのkeyは読み取られる必要がなく、比較すればいいです.
    このアルゴリズムは2つのモードに分かれており、一つは高速モードであり、一つは通常モードである.クイックモードは、keyが順序であると仮定し、高速処理が可能であり、クイック処理が不可能であると発見された場合は、通常モードに戻る.性能を保証しながら、機能に影響を与えません.
    この例では、従来のモードは13個のtokenを処理する必要があり、高速モードは6個のtokenだけを処理する必要がある.
    sort field fast matchアルゴリズムを実現するコードは、このクラスのcomp.aliba.fastjson.parser.deserializer.ASMDeserializer Factoryであり、asmを使用して各タイプのVO動的にクラスを作成して実現します.ここではsort field fast matchアルゴリズムを実証するためのコードがあります. http://code.alibabatech.com/svn/fastjson/trunk/fastjson/src/test/java/data/media/ImageDeserializer.java
    //               
    char[] size_   = "\"size\":".toCharArray();
    char[] uri_    = "\"uri\":".toCharArray();
    char[] titile_ = "\"title\":".toCharArray();
    char[] width_  = "\"width\":".toCharArray();
    char[] height_ = "\"height\":".toCharArray();
    
    //   parse    lexer    
    int mark = lexer.getBufferPosition();
    char mark_ch = lexer.getCurrent();
    int mark_token = lexer.token();
    
    int height = lexer.scanFieldInt(height_);
    if (lexer.matchStat == JSONScanner.NOT_MATCH) {
        //       ,       
        lexer.reset(mark, mark_ch, mark_token);
        return (T) super.deserialze(parser, clazz);
    }
    
    String value = lexer.scanFieldString(size_);
    if (lexer.matchStat == JSONScanner.NOT_MATCH) {
        //       ,       
        lexer.reset(mark, mark_ch, mark_token);
        return (T) super.deserialze(parser, clazz);
    }
    Size size = Size.valueOf(value);
    
    // ... ...
    
    // batch set
    Image image = new Image();
    image.setSize(size);
    image.setUri(uri);
    image.setTitle(title);
    image.setWidth(width);
    image.setHeight(height);
    
    return (T) image;
    3、asmを使って反射を避ける
    deserializeの場合は、asmを使ってオブジェクトを構成し、batch setを作るということは、分散呼出しではなく複数のsetterメソッドを連結して呼び出すことにより、性能を向上させることができます.
    4、utf-8のjson bytesに対して、最適化されたバージョンを用いて符号化を変換する.
    このクラスはcomp.alibabal.fastjson.utill.UTF 8 Decoderで、JDKのUTF 8 Decoderから来ていますが、ThreadLocal Cache Bufferを使って、変換時にchar[]のオーバーヘッドを割り当てることを避けます.ThreadLocal Cacheの実現はこの類のcomp.alibaba.fastjson.util.ThreadLocal Cacheです.初めて1 kです.足りないなら、最大128 kまで成長します.
    //     com.alibaba.fastjson.JSON
    public static final <T> T parseObject(byte[] input, int off, int len, CharsetDecoder charsetDecoder, Type clazz,
                                          Feature... features) {
        charsetDecoder.reset();
    
        int scaleLength = (int) (len * (double) charsetDecoder.maxCharsPerByte());
        char[] chars = ThreadLocalCache.getChars(scaleLength); //   ThreadLocalCache,        
    
        ByteBuffer byteBuf = ByteBuffer.wrap(input, off, len);
        CharBuffer charByte = CharBuffer.wrap(chars);
        IOUtils.decode(charsetDecoder, byteBuf, charByte);
    
        int position = charByte.position();
    
        return (T) parseObject(chars, position, clazz, features);
    }
    5、smbol Tableアルゴリズム.
    私たちはxmlまたはjavacのパーサーの実現を見ています.よく使うキーワードをキャッシュして、char[]を巡回しながらhashを計算して、このhash値をhash tableの中でキャッシュされたsmbolを取得して、新しい文字列オブジェクトを作成しないようにします.このような最適化はfastjsonの中でkeyの読み取りとenum valueの読み取りに用いられます.これはまた、パース性能最適化の鍵となるアルゴリズムの一つである.
    以下はJSONScanner類からのコードで、このコードはenumタイプのvalueを読み出すために使用されます.
    int hash = 0;
    for (;;) {
        ch = buf[index++];
        if (ch == '\"') {
            bp = index;
            this.ch = ch = buf[bp];
            strVal = symbolTable.addSymbol(buf, start, index - start - 1, hash); //   symbolTable       symbol,  fieldName、enumValue
            break;
        }
    
        hash = 31 * hash + ch; //  token scan       hash
    
        // ... ...
    }
    fastjsonを使って何ができますか?
    1、他のすべてのjsonライブラリを交換して、java世界には他のjsonライブラリがありません.fastjsonと比べられます.2、fastjsonを使うプロローグとアンチプログレッシブをJava serializeに置換します.java serializeは性能が遅いだけでなく、体制も大きいです.3、fastjsonを使ってhessianを交替して、json協議とhessian協議の大きさは同じです.そしてfastjsonは性能が優れています.10倍はhessian 4、fastjsonをmemachedに使って対象データをキャッシュします.
    どうやってfastjsonを獲得しますか?
    公式サイト
    Fastjsonはオープンソースで、Apache 2.0プロトコルに基づいています.公式サイトで最新情報を知ることができます. http://code.alibabatech.com/wiki/display/FastJSON/Home
    mavenユーザー
  • Maven倉庫 http://code.alibabatech.com/mvn/releases/
  • <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>1.1.2</version>
    </dependency>
    Binary: http://code.alibabatech.com/mvn/releases/com/alibaba/fastjson/1.1.2/fastjson-1.1.2.jarSource :http://code.alibabatech.com/mvn/releases/com/alibaba/fastjson/1.1.2/fastjson-1.1.2-sources.jarSubversion : http://code.alibabatech.com/svn/fastjson/trunk/fastjson/
    http://code.alibabatech.com/blog/dev_related_1358/fastjson-innside.