Grizzly 的 HTTP CoDec 实现方法更 Netty 的 CoDec 完全不同, 他们思想上的差异主要在于:

1. 解码方式

Grizzly 使用流式解码, 它的HttpHeader对象内部都是用的DataChunk这样的类来存储数据, 就是像是将一个类都分好格子, 里面有 InitialLine, HeaderName1, HederVal1, HeaderName2, HeaderVal2 这样, 这些格子都是用来放二进制数据的, 然后再读取到Buffer后将Buffer的数据往 类里面的格子里填进去. 只有在真正需要使用这些数据的时候才会将二进制数据转为字符串

Netty 的解码则是使用 ReplayingDecoder 的特性来实现, ReplayingDecoder 的特性是可以设置checkpoint, 如果说当前checkpoint还没有完成, 但是buffer的数据又读完了, 则会将当前的数据累计起来, 在下一次收到新buffer的时候从当前checkpoint重新decode, 如果checkpoint完成, 则转移到一下checkpoint, 并释放成功decode的数据. 他的好处在于当buffer被读完的时候(数据不够, 例如header才decode到一半buffer就读完了)则会抛出一个SIGNAL(SIGNAL是Netty自定义的ERROR), 捕捉到这个error以后则会自动累计数据. 这样我们就不需要自己去判断当前数据够不够, 而是当做当前数据已经足够来做decode(因为会自动累计)

在解码方式上, 实际上我更倾向于 Grizzly 的这种方式, 因为它不需要累计数据, 这样就减少了一次ByteBuf的分配, 更节省内存. 而从decode方法上看, 流式填数据decode的方法也更容易理解, 不像replaying decode这么绕难以理解

2. Cache

Grizzly 对 Decode 过程中出现的所有对象都做了Cache, 例如 HttpHeader, HttpContent 等对象, 这些对象的生存周期是整个Decode过程, 也就是在Decode开始的时候会获取这个Cache对象, 然后在Decode完成以后会清理Cache对象内部的数据, 再将它放回 Cache里, 另外, 这些Cache都是ThreadLocal的, 所以他们是肯定线程安全的. 而 Netty 中这些对象都是新生成的. 下面对Grizzly的Cache体系做一个介绍. 这些代码都在 ThreadCache类里.  先看图

最后在看看ThreadCache的代码

public final class ThreadCache {

    private static final ObjectCacheElement[] INITIAL_OBJECT_ARRAY = new ObjectCacheElement[16];

    /** 这个map用于通过className获取对应的CachedTypeIndex */
private static final Map<String, CachedTypeIndex> typeIndexMap =
new HashMap<String, CachedTypeIndex>(); /** 全局的index计数器, 用来初始化CachedTypeIndex */
private static int indexCounter; private static final ThreadLocal<ObjectCache> genericCacheAttr =
new ThreadLocal<ObjectCache>(); public static synchronized <E> CachedTypeIndex<E> obtainIndex(
Class<E> clazz, int size) {
return obtainIndex(clazz.getName(), clazz, size); } /**
* 获取CachedTypeIndex的方法, 也就是说每个类在获取这个CachedTypeIndex的时候,
* 他在ObjectCache的ObjectCacheElement的index就已经定下来了
* */
@SuppressWarnings("unchecked")
public static synchronized <E> CachedTypeIndex<E> obtainIndex(String name,
Class<E> clazz, int size) { CachedTypeIndex<E> typeIndex = typeIndexMap.get(name);
if (typeIndex == null) {
// 注意这里的indexCounter++, 每个类获取一次index就会+1
typeIndex = new CachedTypeIndex<E>(indexCounter++, name, clazz, size);
typeIndexMap.put(name, typeIndex);
} return typeIndex;
} public static <E> boolean putToCache(final CachedTypeIndex<E> index, final E o) {
return putToCache(Thread.currentThread(), index, o);
} public static <E> boolean putToCache(final Thread currentThread,
final CachedTypeIndex<E> index, final E o) {
if (currentThread instanceof DefaultWorkerThread) {
return ((DefaultWorkerThread) currentThread).putToCache(index, o);
} else {
ObjectCache genericCache = genericCacheAttr.get();
if (genericCache == null) {
genericCache = new ObjectCache();
genericCacheAttr.set(genericCache);
} return genericCache.put(index, o);
}
} /**
* Get the cached object with the given type index from cache.
* Unlike {@link #takeFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object won't be removed from cache.
*
* @param <E>
* @param index the cached object type index.
* @return cached object.
*/
public static <E> E getFromCache(final CachedTypeIndex<E> index) {
return getFromCache(Thread.currentThread(), index);
} /**
* Get the cached object with the given type index from cache.
* Unlike {@link #takeFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object won't be removed from cache.
*
* @param <E>
* @param currentThread current {@link Thread}
* @param index the cached object type index.
* @return cached object.
*/
public static <E> E getFromCache(final Thread currentThread,
final CachedTypeIndex<E> index) {
assert currentThread == Thread.currentThread(); if (currentThread instanceof DefaultWorkerThread) {
return ((DefaultWorkerThread) currentThread).getFromCache(index);
} else {
final ObjectCache genericCache = genericCacheAttr.get();
if (genericCache != null) {
return genericCache.get(index);
} return null;
}
} /**
* Take the cached object with the given type index from cache.
* Unlike {@link #getFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object will be removed from cache.
*
* @param <E>
* @param index the cached object type index
* @return cached object
*/
public static <E> E takeFromCache(final CachedTypeIndex<E> index) {
return takeFromCache(Thread.currentThread(), index);
} /**
* Take the cached object with the given type index from cache.
* Unlike {@link #getFromCache(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object will be removed from cache.
*
* @param <E>
* @param currentThread current {@link Thread}
* @param index the cached object type index
* @return cached object
*/
public static <E> E takeFromCache(final Thread currentThread,
final CachedTypeIndex<E> index) {
if (currentThread instanceof DefaultWorkerThread) {
return ((DefaultWorkerThread) currentThread).takeFromCache(index);
} else {
final ObjectCache genericCache = genericCacheAttr.get();
if (genericCache != null) {
return genericCache.take(index);
} return null;
}
} /** 实际存储cache的类 */
public static final class ObjectCache {
private ObjectCacheElement[] objectCacheElements; public boolean put(final CachedTypeIndex index, final Object o) {
if (objectCacheElements != null &&
index.getIndex() < objectCacheElements.length) {
ObjectCacheElement objectCache = objectCacheElements[index.getIndex()];
if (objectCache == null) {
objectCache = new ObjectCacheElement(index.size);
objectCacheElements[index.getIndex()] = objectCache;
} return objectCache.put(o);
} final ObjectCacheElement[] arrayToGrow =
(objectCacheElements != null) ?
objectCacheElements : INITIAL_OBJECT_ARRAY;
final int newSize = Math.max(index.getIndex() + 1,
(arrayToGrow.length * 3) / 2 + 1); objectCacheElements = Arrays.copyOf(arrayToGrow, newSize); final ObjectCacheElement objectCache = new ObjectCacheElement(index.getSize());
objectCacheElements[index.getIndex()] = objectCache;
return objectCache.put(o);
} /**
* Get the cached object with the given type index from cache.
* Unlike {@link #take(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object won't be removed from cache.
*
* @param <E>
* @param index the cached object type index.
* @return cached object.
*/
@SuppressWarnings("unchecked")
public <E> E get(final CachedTypeIndex<E> index) {
final int idx;
if (objectCacheElements != null &&
(idx = index.getIndex()) < objectCacheElements.length) { final ObjectCacheElement objectCache = objectCacheElements[idx];
if (objectCache == null) return null; return (E) objectCache.get();
} return null;
} /**
* Take the cached object with the given type index from cache.
* Unlike {@link #get(org.glassfish.grizzly.ThreadCache.CachedTypeIndex)}, the
* object will be removed from cache.
*
* @param <E>
* @param index the cached object type index.
* @return cached object.
*/
@SuppressWarnings("unchecked")
public <E> E take(final CachedTypeIndex<E> index) {
final int idx;
if (objectCacheElements != null &&
(idx = index.getIndex()) < objectCacheElements.length) { final ObjectCacheElement objectCache = objectCacheElements[idx];
if (objectCache == null) return null; return (E) objectCache.take();
} return null;
}
} public static final class ObjectCacheElement {
private final int size;
private final Object[] cache;
private int index; public ObjectCacheElement(int size) {
this.size = size;
cache = new Object[size];
} public boolean put(Object o) {
if (index < size) {
cache[index++] = o;
return true;
} return false;
} /**
* Get (peek) the object from cache.
* Unlike {@link #take()} the object will not be removed from cache.
*
* @return object from cache.
*/
public Object get() {
if (index > 0) {
final Object o = cache[index - 1];
return o;
} return null;
} /**
* Take (poll) the object from cache.
* Unlike {@link #get()} the object will be removed from cache.
*
* @return object from cache.
*/
public Object take() {
if (index > 0) {
index--; final Object o = cache[index];
cache[index] = null;
return o;
} return null;
}
} public static final class CachedTypeIndex<E> {
private final int index;
private final Class clazz;
private final int size;
private final String name; public CachedTypeIndex(final int index, final String name,
final Class<E> clazz, final int size) {
this.index = index;
this.name = name;
this.clazz = clazz;
this.size = size;
} public int getIndex() {
return index;
} public String getName() {
return name;
} public Class getClazz() {
return clazz;
} public int getSize() {
return size;
}
}
}

最后来看看 CachedTypeIndex 都是在哪里生成的, 以 HttpClientFilter 中的 ClientHttpResponseImpl 为例

private static final class ClientHttpResponseImpl
extends HttpResponsePacket implements HttpPacketParsing { private static final ThreadCache.CachedTypeIndex<ClientHttpResponseImpl> CACHE_IDX =
ThreadCache.obtainIndex(ClientHttpResponseImpl.class, 16);

可见这些Cacheable的类在首次使用的时候就会把这个index给申请下来, 然后在ObjectCache的ObjectCacheElement[]里占上一个位子.之后它的index就已经是固定的了

Grizzly HTTP CoDec ThreadCache 浅析的更多相关文章

  1. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  2. 浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案

    浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案 本文是截止目前为止最强攻略,按照本文方法基本可以无压力应对caffe和Ross B. Girshick的 ...

  3. Netty浅析

    Netty是JBoss出品的高效的Java NIO开发框架,关于其使用,可参考我的另一篇文章 netty使用初步.本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细致的研 ...

  4. protobuf 协议浅析

    目录 Protobuf 协议浅析 1. Protobuf 介绍 1.1 Protobuf 基本概念 1.2 Protobuf 的优点 1.3 Protobuf, JSON, XML 的区别 2. Pr ...

  5. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  6. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  7. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  8. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

  9. 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler

    熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

随机推荐

  1. 001 Ajax中XMLHttpRequest的讲解

    1.介绍 2.方法 3.程序位置设计 4.程序(针对XMLHttpRequest) <%@ page language="java" contentType="te ...

  2. django 不能访问静态资源的解决办法

    最近在中文win10下使用python的django搭建web测试服务器,发现一个诡异的现象,正常配置好django的模型,视图和模板, 1.setting.py内容如下: ""& ...

  3. java微信公众号JSAPI支付以及所遇到的坑

    上周做了个支付宝微信扫码支付,今天总结一下.微信相比支付宝要麻烦许多 由于涉及到代理商,没办法,让我写个详细的申请流程,懵逼啊. 笔记地址 http://note.youdao.com/notesha ...

  4. 使用GenericServlet实例

    使用GenericServlet实例 package com.kettas.servlet; import javax.servlet.* ; import java.io.* ; public cl ...

  5. Web大前端面试题-Day1

    1. var的变量提升的底层原理是什么? JS引擎的工作方式是:1) 先解析代码,获取所有被声明的变量:2)然后在运行.也就是说分为预处理和执行两个阶段. 变量提升:所有变量的声明语句都会被提升到代码 ...

  6. bsgs算法详解

    例题  poj 2417bsgs  http://poj.org/problem?id=2417 这是一道bsgs题目,用bsgs算法,又称大小步(baby step giant step)算法,或者 ...

  7. 我希望我知道的七个JavaScript技巧

    如果你是一个JavaScript新手或仅仅最近才在你的开发工作中接触它,你可能感到沮丧.所有的语言都有自己的怪癖(quirks)——但从基于强类型的服务器端语言转移过来的开发人员可能会感到困惑.我就曾 ...

  8. Codeforces 986D Perfect Encoding FFT

    题意: 给定一个数n,选出m个数使得 $\Pi_{i=1}^m a_i\ge n$,求$\sum_{i=1}^m a_i$的最小值 ,其中$m$的大小不限 $n$的长度$\le 10^6$ 简单的计算 ...

  9. VS2013发布网站删除.CS文件

    VS2013发布网站时,默认不删除.CS文件,想要删除的话,需要一些配置   1.在要发布的网站上右键,选择"发布网站". 2.在发布窗口中,会让你选择一个发布配置文件,没有的话点 ...

  10. Spring boot整合jsp

    这几天在集中学习Spring boot+Shiro框架,因为之前view层用jsp比较多,所以想在spring boot中配置jsp,但是spring boot官方不推荐使用jsp,因为jsp相对于一 ...