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. 远程执行shell

    目前我的需求是在我的hadoop集群搭建起来前,能定时做一下简易指标的监控,目前我的方案就是在我的server机上,定时执行远程脚本出指标数据,然后通过python脚本发送邮件. 远程执行脚本如下: ...

  2. jQuery选择器--简洁又全面(转)

    原文:http://www.cr173.com/html/21124_1.html 选择器是jQuery的根基,在jQuery中,对事件处理.遍历DOM和Ajax操作都依赖于选择器.jQuery选择器 ...

  3. SSH Secure Shell Client安装和使用

    SSH是一个用来替代TELNET.FTP以及R命令的工具包,主要是想解决口令在网上明文传输的问题.为了系统安全和用户自身的 权益,推广SSH是必要的. SSH是英文Secure Shell的简写形式. ...

  4. 浅谈Spring的AOP实现-代理机制

    说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以 ...

  5. git入门教程,主要命令详解。

    准备工作 git clone url / ssh  ----------------------------------------------------------------------从git ...

  6. python全栈开发之正则表达式和python的re模块

    正则表达式和python的re模块 python全栈开发,正则表达式,re模块 一 正则表达式 正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a 到 z 之间的 ...

  7. BZOJ.3998.[TJOI2015]弦论(后缀自动机)

    题目链接 \(Description\) 给定字符串S,求其第K小子串.(若T=0,不同位置的相同子串算1个:否则算作多个) \(Solution\) 建SAM,处理出对于每个节点,它和它的所有后继包 ...

  8. BZOJ4277 : [ONTAK2015]Cięcie

    假设分成如下三段: [1..i][i+1..j][j+1..n] 考虑中间那一段,设f[i]为前i位组成的数模q的值,pow[i]为$10^i$模q的值,那么有: f[j]-f[i]*pow[j-i] ...

  9. FireDAC 下的 Sqlite [11] - 关于批量提交 SQL 命令的测试

    可把下面代码直接贴在空白窗体上, 以快速完成窗体设计: object DBGrid1: TDBGrid Left = 0 Top = 0 Width = 265 Height = 338 Align ...

  10. c# 实现获取汉字十六进制Unicode编码字符串

    1.  汉字转十六进制UNICODE编码字符串 /// <summary>        /// ////        /// </summary>        /// & ...