超人汪小建(seaboat)
公众号:【远洋号】,笔名seaboat,擅长工程算法、人工智能算法、自然语言处理、计算机视觉、架构、分布式、高并发、大数据和搜索引擎等方面的技术,大多数编程语言都会使用,但更擅长Java、Python和C++。平时喜欢编程、绘画、看书、写作和运动,擅长素描、篮球、跑步、游泳、健身和羽毛球等运动项目。崇尚技术自由,崇尚思想自由。出版书籍:《Tomcat内核设计剖析》、《图解数据结构与算法》、《图解Java并发原理》、《人工智能原理科普》。
展开
-
设计一个中间件的访问日志组件
对任何一个系统,一个强大的日志记录功能是相当重要且必要的,根据日志的记录可以及时掌握系统运行时的健康状态及故障定位。然而作为web容器存在另外一种日志——访问日志。访问日志一般会记录客户端的访问相关信息,包括客户端ip、请求时间、请求协议、请求方法、请求字节数、响应码、会话id、处理时间等等。通过访问日志可以统计访问用户的数量、访问时间分布等规律及个人爱好等等,而这些数据可以帮助公司在运营策略上做原创 2015-06-07 09:48:44 · 3161 阅读 · 2 评论 -
集群通信组件Tribes之如何维护集群成员信息
一个集群包含若干成员,要对这些成员进行管理就必须要有一张包含所有成员的列表,当要对某个节点做操作时通过这个列表可以准确找到该节点的地址进而对该节点发送操作消息。如何维护这张包含所有成员的列表是本节要讨论的主题。成员维护是集群的基础功能,一般划分一个独立模块或层完成此功能,它提供成员列表查询、成员维护、成员列表改变事件通知等能力。由于tribes定位于基于同等节点之间的通信,所以并不存在主节点选举的原创 2015-07-12 14:10:51 · 2761 阅读 · 1 评论 -
集群通信组件tribes之集群的平行通信
前面的集群成员维护服务为我们提供了集群内所有成员的地址端口等信息,可以通过MembershipService可以轻易从节点本地的成员列表获取集群所有的成员信息,有了这些成员信息后就可以使用可靠的TCP/IP协议进行通信了。这节讨论的正是实际中真正用于消息传送通道的相关机制及实现细节。如下图,四个节点本地都拥有了一张集群成员的信息列表,这时节点1有这么一个需求:为了保证数据的安全可靠,在往自己的内存原创 2015-07-18 21:07:23 · 3037 阅读 · 1 评论 -
Tomcat中定制阀门
我们说管道机制给我们带来了更好的扩展性,Tomcat中在扩展性方面具体如何体现,这便是本节讨论的内容。从上节了解到基础阀门是必须执行的,假如你需要一个额外的逻辑处理阀门,可以添加一个非基础阀门。我的需求是对每个请求访问进行IP记录,打印到日志里面,详细操作如下:① 自定义一个阀门PrintIPValve,只要继承ValveBase并重写invoke方法即可,ValveBase是Tomcat原创 2015-05-17 18:45:26 · 4467 阅读 · 5 评论 -
Http协议处理器——Http11Processor
Http11Processor组件提供了对Http协议通信的处理,包括对套接字的读取过滤、对http协议的解析并封装成请求对象、http响应对象的生成、套接字的过滤写入等等操作。原创 2015-04-19 10:11:52 · 4394 阅读 · 0 评论 -
小文本——Cookies
http协议的无状态性导致在需要会话的场景下寸步难行,例如一个网站为了方便用户,在一段时间内登录过改网站的浏览器客户端实现自动登录,为实现这种客户端与服务器之间的会话机制需要额外的一些标识,http头部引入的Cookies正是客户端与服务器会话机制的基础。当一个浏览器通过http协议访问某服务器时,服务器可以将指定的一些键值对发往客户端,客户端根据域名保存于本地,下次访问此域名时浏览器会连同此些键原创 2015-03-15 16:17:11 · 2182 阅读 · 0 评论 -
java组播MulticastSocket
在单播模式中有服务器端和客户端之分,而组播模式与单播模式不同,每个端都是以路由器或交换机做为中转广播站,任意一端向路由器或交换机发送消息,路由或交换机负责发送其他节点,每个节点都是同等的。所以在编程模式上用同一个类表示即可——MulticastSocket。 MulticastSocket属于jdk提供的类,类路径为java.net.MulticastSocket,利用此类可以很方便地实现组原创 2015-05-31 21:43:37 · 6591 阅读 · 3 评论 -
讲究门面的Request
为什么说Request讲究门面?注意这里所说的门面并非我们常理解的外表的意思,其实是说它使用了门面设计模式,门面的使用主要用于数据安全的考虑。一个大的系统体系的多个子系统之间涉及交互通信、一个系统中的多个子组件之间同样可能涉及数据交互,但考虑到安全问题,某一子系统或子组件不可能把自己内部数据过多地暴露给其他子系统或子组件,这时就要门面模式出马了,将某一子系统或子组件设计成一个门面,把别的子系统或子原创 2015-03-14 13:19:48 · 2282 阅读 · 0 评论 -
输入过滤器——InputFilter
一般情况下我们通过请求体读取器InputStreamInputBuffer获取的仅仅是源数据,即未经过任何处理发送方发来的字节。但有些时候在这个读取的过程中希望做一些额外的处理,并且这些额外处理可能是根据不同条件做不同的处理,考虑到程序解耦与扩展,于是引入过滤器(过滤器模式)——输入过滤器InputFilter。在读取数据过程中对于额外的操作只需要通过添加不同的过滤器即可实现,例如添加对http1原创 2015-03-22 11:57:04 · 4931 阅读 · 0 评论 -
集群通信组件Tribes之整体介绍
接下来一系列文章会对集群通信框架tribes进行源码级别的分析,欢迎讨论。把若干机器组合成一个集群,集群为了能协同工作,成员之间的通信是必不可少的,当然可以说这也是集群实现中重点需要解决的核心问题,一个强大的通信协同机制是集群的基础。简约地说,Tribes是一个具备让你通过网络向组成员发送和接收信息、动态检测发现其他节点的组通信能力的高扩展性的独立的消息框架。在组成员之间进行信息复制及成员维护是一原创 2015-07-04 15:35:11 · 3591 阅读 · 1 评论 -
访问日志格式的自定义
在第一小节中经过几步一个访问日志组件已成型,但为了增加用户自定义能力我们还是要继续做点事,对于用户自定义的实现最经典的做法就是引入变量表示,例如定义%a表示远程主机IP、%A表示本机IP等等,然后在写入之前用相应逻辑把变量替换成相应的值写入日志。这节我们来实现日志格式的自定义支持。整个过程其实是先自定义变量组,再逐个把变量替换成相应值,最后把替换后的值写入文件。由于需要实现很多不同的变量,所以定义原创 2015-06-14 10:26:50 · 2498 阅读 · 1 评论 -
集群
集群现在如果要构造一个真正在生产环境上可使用的可靠的系统,基本都离不开集群的概念,总的来说集群是指由若干互相独立的机器通过高速网络组成的一个整体服务,整个集群的内部实现相对外部是透明的,对外部而言它就像一个独立的服务器。要使若干机器协同工作不是一件简单的事,其核心是如何在多机器之间进行通信及各种任务调度使之协同工作。在工程上常见的两种集群是——负载均衡集群和高可用集群。负载均衡集群(Load原创 2015-06-27 18:35:19 · 2568 阅读 · 1 评论 -
访问日志IO性能优化
在高并发量的场景下磁盘IO往往是性能的瓶颈所在,访问日志涉及到频繁的写操作,所以这部分要尽可能地优化,不然将拖累系统的整体性能。针对文件记录及数据库记录两种方式可以有以下措施提高写性能,l 避免频繁的打开关闭文件。将日志写入文件的一般操作步骤是打开-写入-关闭,但假如在需要频繁写入日志的场景下,这种方式在性能上肯定会存在问题,因为每次打开关闭都是需要成本开销的,所以必须要想想是否有别的更好的方式,原创 2015-06-21 14:56:10 · 5223 阅读 · 1 评论 -
Tomcat的管道
Tomcat中按照包含关系一共有四个容器——StandardEngine、StandardHost、StandardContext和StandardWrapper,对这四个容器的详细解析后面会涉及,请求对象及响应对象将分别被此四个容器处理,请求响应对象在四个容器之间通过管道机制进行传递。如下图,请求响应对象先通过StandardEngine的管道,期间经过若干个阀门处理,基础阀门是Standard原创 2015-05-10 17:28:58 · 3968 阅读 · 4 评论 -
任务定义器——SocketProcessor
将socket扔进线程池前需要定义好任务,要进行哪些逻辑处理由SocketProcessor定义,根据线程池的约定,作为任务必须扩展Runnable。用如下伪代码表示protected class SocketProcessor implements Runnable { public void run() {对socket进行处理并输出响应报文;连接数计数器减一腾出原创 2015-02-08 19:31:23 · 2832 阅读 · 0 评论 -
Socket接收器——Acceptor
Acceptor是JIoEndpoint的内部类,主要的职责就是监听是否有客户端套接字连接并接收socket,再将socket交由任务执行者(Executor)执行。不断从系统底层读取socket,接着做尽可能少的处理(最好就是接收到后不做任何处理),最后扔进线程池。为什么强调要做尽可能少的处理?这里关系到系统性能问题,过多的处理会严重影响吞吐量。因为tomcat默认只有一个接收器(一条线程负责套原创 2015-02-01 19:47:35 · 3398 阅读 · 8 评论 -
Java并发——线程池原理
“池”技术对我们来说是非常熟悉的一个概念,它的引入是为了在某些场景下提高系统某些关键节点性能,最典型的例子就是数据库连接池,JDBC是一种服务供应接口(SPI),具体的数据库连接实现类由不同厂商实现,数据库连接的建立和销毁都是很耗时耗资源的操作,为了查询数据库中某条记录,最原始的一个过程是建立连接、发送查询语句、返回查询结果、销毁连接,假如仅仅是一个很简单的查询语句,那么可能建立连接与销毁连接两个原创 2015-01-24 19:56:15 · 4780 阅读 · 2 评论 -
头部——MimeHeaders
http协议的请求头部更像一个键值对,例如Content-Length : 123,前面为键后面为值,表示文本长度为123。对于若干个头部在请求对象中被封装成MimeHeaders对象,MimeHeaders对象里面包含了一个链表结构用于存放头部名和头部值。如下图上,每个MimeHeaderField对象指向其前驱节点对象,同时也指向其后继节点对象,采用这种双向链表结构有利于快速搜索,另外也有助于原创 2015-03-06 08:28:13 · 3480 阅读 · 0 评论 -
套接字输入流——InputStream
输入缓冲装置里面必须要包含读取字符的通道,否则就谈不上缓冲了,这个通道就是InputStream,它属于jdk中java.io包的类,有了它我们就可以从源头读取字符,它的来源可以有多种多样,这里主要探讨的是从socket连接中读取字符。如上图,InputStream充当从操作系统底层读取socket字节的通道,当客户端与服务器端建立起连接后就可以看成存在一条通道供双方传递信息,客户原创 2015-02-19 23:22:55 · 2991 阅读 · 0 评论 -
套接字输入缓冲装置——InternalInputBuffer
互联网的世界很复杂,信息从一端传向另一端过程也相当复杂,中间可能通过若干个硬件,为了提高发送和接收效率,在发送端及接收端都将引入缓冲区,所以两端的套接字都拥有各自的缓冲区,当然这种缓冲区的引入也带来了不确定的延时,在发送端一般先将消息写入缓冲区,直到缓冲区填满才发送,而接收端则一次只读取最多不超过缓冲区大小的消息。Tomcat在处理客户端的请求时需要读取客户端的请求数据,它同样需要一个缓冲区用原创 2015-02-24 21:33:07 · 2918 阅读 · 0 评论 -
任务执行器——Executor
上节说到接收器Acceptor在接收到socket后会有一系列简单的处理,其中将socket扔进线程池是最重要的一步,线程池是一个怎样东西?其原理在前面的“线程池原理”章节已经说明过了,这里重点讲tomcat中用于处理客户端请求的线程池——Executor。为确保整个web服务器的性能,应该在接到请求后以最快的速度转交到其他线程上去处理。在接收到客户端的请求后tomcat将对这些请求交给任务执原创 2015-02-07 19:21:27 · 2776 阅读 · 0 评论 -
消息字节——MessageBytes
在tomcat核心处理中有这么一个需求——“为了提高编码性能,对于socket接收到的字节流不马上进行某种编码的转码,而是应该保留字节流的形式,在需要时、在指定编码时才进行转码工作”。MessageBytes正是为解决这个问题而提出的一个类。消息字节封装了不同类型方式用于表示信息,它包含了四种类型:T_BYTES、T_CHARS、T_STR、T_NULL,分别表示字节类型、字符类型、字符串类型原创 2015-03-01 19:05:22 · 3518 阅读 · 0 评论 -
Tomcat内核之ASCII解码的表驱动模式
我们知道Tomcat通信是建立在Socket的基础上,而套接字在服务器端和客户端传递的报文都是未经过编码的字节流,每8位组成1个字节,计算机以二进制为基础,这是由于使用晶体管的开合状态表示1和0,这样8个电晶体管就可以组成一个字节,这正是应用层使用的最小单位——字节。在通过Socket进行网络通信的程序中,假如我们在接收到报文时不知道通过什么编码才能正确解码,最好的办法就是用Socket最底层原创 2015-01-17 19:57:02 · 2690 阅读 · 0 评论 -
Tomcat内核之Tomcat的类加载器
跟其他主流的Java Web服务器一样,Tomcat也拥有不同的自定义类加载器,达到对各种资源库的控制。一般来说,Java Web服务器需要解决以下四个问题:① 同一个Web服务器里,各个Web项目之间各自使用的Java类库要互相隔离。② 同一个Web服务器里,各个Web项目之间可以提供共享的Java类库。③ 服务器为了不受Web项目的影响,应该使服务器的类库与应用程序的类原创 2014-12-14 20:25:13 · 4905 阅读 · 0 评论 -
Tomcat内核之类加载器工厂
Java虚拟机利用类加载器将类载入内存,以供使用。在此过程中类加载器要做很多的事情,例如读取字节数组、验证、解析、初始化等。而Java提供的URLClassLoader类能方便地将jar、class或网络资源加载到内存。Tomcat中则用一个工厂类ClassLoaderFactory把创建类加载器的细节进行封装,通过它可以很方便地创建自定义的类加载器。 如上图,利用createClassL原创 2014-12-19 22:51:15 · 2609 阅读 · 0 评论 -
套接字工厂——ServerSocketFactory
接收器Acceptor在接收连接的过程中,根据不同的使用场合可能需要不同的安全级别,例如在支付相关的交易就必须对信息加密后再发送,这其中还涉及到密钥协商的过程,而在另外一些普通场合则无需对报文加密。反应到应用层则是使用http与https的问题,具体跟http/https相关的一些知识请到前面相关章节温习。看一张跟https协议的组成层次图,它在应用层添加了一个TLS\SSL协议,于是组成了h原创 2015-02-16 19:21:50 · 4920 阅读 · 0 评论 -
流量控制闸门——LimitLatch套接字连接数限制器
Tomcat作为web服务器,对于每个客户端的请求将给予处理响应,但对于一台机器而言,访问请求的总流量有高峰期且服务器有物理极限,为了保证web服务器不被冲垮我们需要采取一些措施进行保护预防,需要稍微说明的此处的流量更多的是指套接字的连接数,通过控制套接字连接个数来控制流量。其中一种有效的方法就是采取流量控制,它就像在流量的入口增加了一道闸门,闸门的大小决定了流量的大小,一旦达到最大流量将关闭闸门原创 2015-01-25 19:42:54 · 3906 阅读 · 2 评论 -
tomcat启动批处理——setclasspath.bat
除了上面两个批处理,还有一个比较重要的脚本,即是setclasspath.bat,它主要负责寻找、检查JAVA_HOME和JRE_HOME两个变量。********************************************************************************************if ""%1"" ==""debug"" goto nee原创 2014-10-31 22:15:53 · 3296 阅读 · 0 评论 -
Tomcat中的ssl安全信道的实现
为了实现https协议通信,tomcat需要利用JSSE把SSL/TLS协议集成到自身系统上,通过上一节我们知道不同的厂商可以实现自己的JSSE,而tomcat默认使用的是以前sun公司开发实现的包而且由JDK自带。Tomcat实现http及https通信的基础是什么?其实http与https的不同就是在创建通信套接字服务器时的不同,http是没有任何加密措施的套接字服务器,而https是靠嵌原创 2014-11-03 23:46:31 · 4859 阅读 · 0 评论 -
tomcat启动批处理——catalina.bat
这个批处理才是tomcat服务器启动跟关闭的核心脚本。其中包括。。。。(各种变量),此节将详细讲解这个批处理的逻辑。先看看第一部分脚本:********************************************************************************************if not ""%1"" == ""run"" goto main原创 2014-10-27 20:58:15 · 5200 阅读 · 0 评论 -
Tomcat的系统安全管理
Tomcat是一个Web容器,我们开发的Web项目运行在Tomcat平台,这就好比将一个应用嵌入到一个平台上面运行,要使嵌入的程序能正常运行,首先平台要能安全正常运行。并且要最大程度做到平台不受嵌入的应用程序影响,两者在一定程度上达到隔离的效果。Tomcat与Web项目也是要最大程度隔离,使Tomcat平台足够安全。我们先看看Tomcat可能存在哪些安全威胁。(1) 在web应用的jsp页原创 2014-10-20 19:58:21 · 4164 阅读 · 1 评论 -
tomcat启动批处理——startup.bat
从文件命名上看就知道这是一个启动批处理,这个批处理的主要功能就是为了找到另一个批处理catalina.bat,并且执行catalina.bat。一开始就用if "%OS%" == "Windows_NT" setlocal 判断系统是否为Windows_NT,如果是的话则使用setlocal命令,此命令表示之后所有对环境变量的改变只限于该批处理文件,要还原原先的设置可以执行endlocal,如原创 2014-10-23 19:56:57 · 5161 阅读 · 0 评论 -
多线程之Java线程阻塞与唤醒
线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节。在Java发展史上曾经使用suspend()、resume()方法对于线程进行阻塞唤醒,但随之出现很多问题,比较典型的还是死锁问题。如下代码,主要的逻辑代码是主线程启动线程mt一段时间后尝试使用suspend(原创 2014-12-06 18:58:01 · 14373 阅读 · 1 评论 -
tomcat生命周期的管理——生命周期统一接口Lifecycle
我们知道Tomcat的架构设计是清晰的、模块化的,其拥有很多组件,假如我们要启动Tomcat,可以一个一个启动组件,但这样启动有很多缺点,不仅麻烦,而且容易漏了组件启动,还会对后面动态组件扩展带来麻烦。难不成真要我们一个一个启动吗?其实未必,Tomcat的设计者提供了一个解决方案:用Lifecycle管理启动、停止、关闭。从第一节的架构图可以看到各个核心组件有包含与被包含的关系,例如Ser原创 2014-11-04 21:27:49 · 4705 阅读 · 0 评论 -
socket系列之socket服务端与客户端如何通信
上面已经分别介绍了ServerSocket跟Socket的工作步骤,并且从应用层往系统底层剖析其运作原理,我们清楚了他们各自的一块,现在我们将把他们结合起来,看看他们是如何通信的,并详细讨论一下他们之间相互通信的一些细节。借助图2-3-2-4,想象一下你正在大学课室上着电脑,你跟你另外两个朋友觉得老师讲得课很菜,没必要听,于是你们仨都各自打开浏览器冲浪,刚好你们访问了同一台服务器,假如你用的是原创 2014-12-07 21:50:20 · 3901 阅读 · 0 评论 -
socket系列之什么是socket
1、什么是socketSocket是应用层与TCP/IP协议族通信的中间抽象层,它是一组接口,应用层通过调用这些接口实现发送和接收数据。一般这种抽象层由操作系统提供或者由JVM自己实现。使用socket可以简单地实现应用程序在网络上得通信,一台机器上的应用想socket写入信息,另外一台相连的机器能读取到。TCP/IP协议族中分两种socket类型,分别是流套接字和数据报套接字,分别对应TCP原创 2014-11-22 23:53:59 · 3140 阅读 · 0 评论 -
socket系列之客户端socket——Socket类
假设TCP套接字服务器端已经建立好并正在监听客户端的连接了,那么客户端就可以通过Socket类来发起连接。客户端发起一个连接请求后,就被动地在等待服务器的响应。这个类同样位于java.net包中,包含很多方法用于建立连接,操作数据流等。客户端按以下几步进行工作:① 创建一个Socket实例,构造函数直接指定远程服务器IP跟端口,建立一个TCP连接。② 通过这个Socket实例的输入输出流进原创 2014-12-05 20:49:57 · 2395 阅读 · 2 评论 -
J2EE规范标准
J2EE是一个很大的平台体系,提供了很多服务、程序接口、协议等。这么庞大的体系必须要由一系列的标准进行规范,不然将会一片混乱。通过这些规范好的接口来开发程序将会使程序更加强壮、更加有生命力。总的来说,规范是一种抽象思维的体现,它的好处就是达到了约束所有厂商的效果,抽象出一个统一的规范接口,使我们在编程时使用统一的接口,兼容性得到保证,与底层具体实现达到高度隔离解耦。我们知道,J2EE有十三个规范,原创 2014-11-16 22:41:42 · 2571 阅读 · 0 评论 -
tomcat如何避免遭遇ClassNotFoundException
在Tomcat中为什么创建类加载器后马上就Thread.currentThread().setContextClassLoader(catalinaLoader)?这里主要是为了避免后面加载类时加载失败。下面将举一个典型的例子说明如何利用URLClassLoader加载指定的jar包,并且解析由此引出的加载失败问题。首先,定义一个提供服务的接口,并且打包成TestInterface.jar。原创 2014-10-19 00:31:29 · 7182 阅读 · 5 评论 -
socket系列之服务器端socket——ServerSocket类
一般地,Socket可分为TCP套接字和UDP套接字,再进一步,还可以被分为服务器端套接字跟客户端套接字。这节我们先关注TCP套接字的服务器端socket,Java中ServerSocket类与之相对应,这个类主要用于如何在服务器端创建一个套接字服务,建立一个通信终端,被动地等待客户端的连接,一旦有数据进入被监听的端口,这个类将能接收这些数据。ServerSocket类位于java.net包中原创 2014-11-30 22:23:44 · 3481 阅读 · 0 评论