jetty9優化的兩處地方

zhanlijun發表於2014-04-01

http://www.cnblogs.com/LBSer/p/3637387.html

jetty 9兩個優化:

https://webtide.intalio.com/2013/01/jetty-9-goes-fast-with-mechanical-sympathy/?utm_source=tuicool

1. False Sharing in Queues

原先使用了 BlockingArrayQueue,這個queue有頭尾兩個指標,生產和消費是獨立的,但是會產生這樣一個問題;“However because of the layout in memory of the class, it turned out that the head and tail pointers and locks were all within a single CPU cache row。This is bad because when different threads running on different cores are trying to independently work on the head and tail, it turns out that they are both hitting the same area of memory and are thus repeatedly invalidating each others caches in a pattern called false sharing

解決方法:

The solution is to be aware of the memory layout of the class when considering what threads will be accessing which fields and to space them out so that you can avoid thisfalse sharing of cache rows. 

從程式碼上看(http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingArrayQueue.java):

public class BlockingArrayQueue<E> extends AbstractList<E> implements BlockingQueue<E>
{
    /**
     * The head offset in the {@link #_indexes} array, displaced by 15 slots to avoid false sharing with the array length (stored before the first element of
     * the array itself).
     */
    private static final int HEAD_OFFSET = MemoryUtils.getIntegersPerCacheLine() - 1;
    /**
     * The tail offset in the {@link #_indexes} array, displaced by 16 slots from the head to avoid false sharing with it.
     */
    private static final int TAIL_OFFSET = HEAD_OFFSET + MemoryUtils.getIntegersPerCacheLine();
    /**
     * Default initial capacity, 128.
     */
    public static final int DEFAULT_CAPACITY = 128;
    /**
     * Default growth factor, 64.
     */
    public static final int DEFAULT_GROWTH = 64;

    private final int _maxCapacity;
    private final int _growCapacity;
    /**
     * Array that holds the head and tail indexes, separated by a cache line to avoid false sharing
     */
    private final int[] _indexes = new int[TAIL_OFFSET + 1];
    private final Lock _tailLock = new ReentrantLock();
    private final AtomicInteger _size = new AtomicInteger();
    private final Lock _headLock = new ReentrantLock();
    private final Condition _notEmpty = _headLock.newCondition();
    private Object[] _elements;
...
}

 

2. Time and Space Efficient Trie

  解析HTTP Header的時候,我們常常需要將在ByteBuffer的資料(ByteBuffer不在jvm記憶體中)轉換成String類,通常還放到一個hashmap中,這樣會產生大量的開銷(建立物件耗時,記憶體消耗)。jetty9為了不將ByteBuffer的資料進行轉換,不採用hashmap,而使用trie這種資料結構。

  jetty程式碼提交者們使用了不同型別的trie進行嘗試。1)首先使用了TreeTrie,但是TreeTrie缺乏空間區域性性,效能較差;2)之後使用ArrayTrie ,但是ArrayTrie 記憶體開銷過大,當有成千上萬請求時可能會造成GC問題;3)最終使用了 ArrayTernaryTrie(http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-util/9.1.0.v20131115/org/eclipse/jetty/util/ArrayTernaryTrie.java), ArrayTernaryTrie節省空間,且查詢速度不低於hashmap。

 

3. 效能評測

  “Thus for a small increase in static heap usage (0.5MB in the static Tries), jetty-9 out performs jetty-8 by 30% faster (33.5s vs 48.6s) and 50% less YG garbage (1409MB vs 2914MB) which trigger less than half the YG collections.”

 

ternary-search-tree參考文獻:

http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/ 

相關文章