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. ZOJ Monthly, March 2018 题解

    [题目链接] A. ZOJ 4004 - Easy Number Game 首先肯定是选择值最小的 $2*m$ 进行操作,这些数在操作的时候每次取一个最大的和最小的相乘是最优的. #include & ...

  2. 004.SMB之guest级别配置

    一 配置文件修改 注意: 1 share级别权限访问即,无任何验证共享,对guest开放. 2 新版samba4已取消share级别,可使用user级别配置成无验证共享. 1.1 全局配置文件修改 [ ...

  3. WIN10下 VS2017+OpenCv 3.4.1 配置

    写篇博客来记录一下opencv在VS中的配置. 一.下载OpenCv安装包 下载的途径有三种: 1.官网下载 但是官网下载真的是贼头大,首先下载好好的突然说下载中断,而且无法恢复,此外,还慢,毕竟外网 ...

  4. C#开发Unity游戏教程之判断语句

    C#开发Unity游戏教程之判断语句 游戏执行路径的选择——判断 玩家在游戏时,无时无刻不在通过判断做出选择.例如,正是因为玩家做出的选择不同,才导致游戏朝着不同的剧情发展,因此一个玩家可以对一个游戏 ...

  5. Ubuntu 18.04 更新源

    [原因] 使用国外的源,在更新软件的时候会很慢,换成国内的源会快很多. [命令] 1.备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list ...

  6. Codeforces.744B.Hongcow's Game(交互 按位统计)

    题目链接 \(Description\) 一个\(n\times n\)的非负整数矩阵\(A\),保证\(A_{i,i}=0\).现在你要对每个\(i\)求\(\min_{j\neq i}A_{i,j ...

  7. Java可视化编程---SendMail工具的开发

    介绍: SendMail是一款简便的163邮箱发件工具 利用了163的SMTP接口来发送邮件 版本号:SendMail v1.0 在编写发送邮件工具之前,还需要安装 JavaMail API 和Jav ...

  8. js获取鼠标点击事件的相对位置

    <html><head><title>位置</title><script language="javascript" type ...

  9. Sublime Text 2 快捷键(转)

    文件 File 新建文件 Ctrl + N 打开文件 Ctrl + O 打开最近关闭的文件 Ctrl + Shift + T 保存 Ctrl + S 另存为… Ctrl + Shift + S 关闭文 ...

  10. 【Go入门教程2】基本构成元素:标识符(identifier)、关键字(keyword 25个)、字面量(literal)、分隔符(delimiter)、和 操作符(operator)

    基本构成要素 Go 的语言符号 又称 词法元素,共包括 5 类内容——标识符(identifier).关键字(keyword).字面量(literal).分隔符(delimiter) 和 操作符(op ...