- 浏览: 1598206 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
jsrgzhangzhiyong:
关于null值的转换还是感觉不太友好,就像 mapstruct ...
我也造了个轮子:BeanMapping(属性拷贝) -
he037:
a417930422 写道引用使用EPHEMERAL会引出一个 ...
基于zookeeper的分布式lock实现 -
seancheer:
qianshangding 写道首先节点启动后,尝试读取本地的 ...
zookeeper学习记录三(session,watcher,persit机制) -
雪夜归人:
您好,我想咨询一下,开源的canal都能支持mysql的哪些版 ...
Canal BinlogChange(mysql5.6) -
zhoudengyun:
copy 一份做记录,后续学习,请知悉
阿里巴巴开源项目: 基于mysql数据库binlog的增量订阅&消费
继上一篇文章: HttpClient超时机制(安全问题处理:访问超大文件控制)
提到了一个需要管理所有request请求的timeout,原先文章的一种处理方式是起一个异步线程的方式,通过jdk的unsafe的await机制控制timeout。
存在的问题:
1. 创建新线程的开销不小。
2. 大量线程的调度和切换,引起不必要的context switch
和同事在沟通的过程中,提到一种新思路,就是有一个monitor线程来管理所有request的timeout。
- 启动一个monitor thread,是一个while true运行
- 每个请求创建之前都先注册到monitor,比如什么时候过期和对应的request句柄,完成后注销。
- 运行的monitor,定时读取注册的request信息,发现有数据过期时间到了,直接拿到request引用,执行强制关闭。
针对monitor timeout调度设计时,也想过几种思路:
思路1: 插入o(1) + 调度o(N)+ 主动轮询式
维护一个list队列,monitor线程间隔固定频遍历一次list队列。挑出时间已经过期的数据,执行关闭。
思路2: 插入o(logN) + 调度o(1) + 主动轮询式
维护一个有序队列(根据距离过期时间最近做升序排序),monitor线程间隔固定频取出头节点,进行关闭处理。
思路3: 插入o(logN) + 调度o(1) + 阻塞通知式
维护一个二叉树(根据距离过期时间最近做升序排序),monitor阻塞于二叉树队列,获取头节点,通过signal方式唤醒。
很明显,思路3在处理上比较靠谱,性能上和处理成本比较好。
二叉树第一直觉就是选择PriorityQueue或者TreeMap。
PriorityQueue是一个基于object[]数组实现的二叉树,而TreeMap走的是红黑树,比较传统的left,right节点的树实现。
考虑再加上timeout时间需要进行delay处理,最后就有一个不二之选DelayQueue了,其内部包含了一个PriorityQueue做为其数据存储。
DelayQueue的Item对象是需要实现Delayed接口
public interface Delayed extends Comparable<Delayed> { long getDelay(TimeUnit unit); }
说明:getDelay主要返回对应距离目标time还存在剩余的delay时间。这里插入一个request后,立马调用该方法返回的应该就是你想要的timeout时间。
代码实现:
/** * 超时控制线程,基于DelayQueue实现的一套超时管理机制 * * <pre> * 几个特点 * 1. O(logN)的超时控制算法 * 2. timout处理更精确,时间控制精度为毫秒(ms) * 3. thread-safe(线程安全) * </pre> * * @author jianghang 2011-3-7 下午12:39:17 */ class HttpTimeoutThread extends Thread { // init time for nano private static final long MILL_ORIGIN = System.currentTimeMillis(); // thread-safe,定时触发timeout private volatile DelayQueue<HttpTimeoutDelayed> queue = new DelayQueue<HttpTimeoutDelayed>(); public void run() { while (true) { try { HttpTimeoutDelayed delay = this.queue.take(); delay.doTimeout(); } catch (InterruptedException e) { // ignore interrupt } } } public void addHttpRequest(HttpClientRequest request, long timeout) { this.queue.put(new HttpTimeoutDelayed(request, timeout)); } // 内部timeout Delay控制 class HttpTimeoutDelayed implements Delayed { private HttpClientRequest request; // 管理对应的request private long now; // 记录具体request产生时的now的偏移时间点,单位ms private long timeout; // 记录具体需要被delayed处理的偏移时间点,单位ms public HttpTimeoutDelayed(HttpClientRequest request, long timeout){ this.request = request; this.timeout = timeout; this.now = System.currentTimeMillis() - MILL_ORIGIN; } /** * 对应的超时处理 */ public void doTimeout() { this.request.forceRelease();// 强制关闭对应的链接 } @Override public long getDelay(TimeUnit unit) { long currNow = System.currentTimeMillis() - MILL_ORIGIN; long d = unit.convert(now + timeout - currNow, TimeUnit.MILLISECONDS); return d; } @Override public int compareTo(Delayed other) { if (other == this) { // compare zero ONLY if same object return 0; } else if (other instanceof HttpTimeoutDelayed) { HttpTimeoutDelayed x = (HttpTimeoutDelayed) other; long diff = now + timeout - (x.now + x.timeout); return diff < 0 ? 1 : (diff > 0 ? 1 : (now > x.now ? 1 : -1)); // 相等情况按照插入时间倒序 } else { long d = (getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS)); return (d == 0) ? 0 : ((d < 0) ? -1 : 1); } } } }
启动Thread :
private static HttpTimeoutThread timeoutGuard = null;
static {
timeoutGuard = new HttpTimeoutThread();
timeoutGuard.setDaemon(true); // 设置为daemon线程,允许主进程关闭后退出
timeoutGuard.setName("HttpClientHelper Timeout Guard");
timeoutGuard.start(); // 启动
}
//注册request到monitor线程
HttpClientHelper.timeoutGuard.addHttpRequest(request, connectTimeOut + waitDataTimeOut);
后记:
最后思考一下timeout的处理机制,就类似于一个定时器的概念,只不过这个定时器执行一次。所以最后也查了下linux的定时器调度算法,前面3种思路也是大同小异。
现在linux操作系统使用的应该是wheel调度算法,具体可以参看一篇IBM的文章: Linux 下定时器的实现方式分析
其对应的几种算法复杂度:
实现方式 | StartTimer | StopTimer | PerTickBookkeeping |
基于链表 | O(1) | O(n) | O(n) |
基于排序链表 | O(n) | O(1) | O(1) |
基于最小堆 | O(lgn) | O(1) | O(1) |
基于时间轮 | O(1) | O(1) | O(1) |
ps : 最后感慨一下,java的确给我们封装了很多不错的工具包,比较方便。java.util.*还是有许多比较不错的算法和实现,可以深挖下。
评论
得抽空看看netty的源码实现,一直想看mina和netty的源码可一直没时间
因为我完全是一个对外系统的访问,对应url都是客户输入,重用链接没任何意义,用完一次就可以关闭。
我这里使用MultiThreadedHttpConnectionManager并不是为了共享连接。而是利用了它可以强制关闭链接的功能。
其他我找不到相应的public入口操作http socket链接,不过非正常手段到可以用反射,不是很愿意这么搞。
正如上一篇文件描述的,如果给定的一部电影的url地址,链接会一直不能被关闭,直到数据流被读完,如果来个几十次这样的请求,应用估计也差不多崩溃了。
目前httpClient3.1只支持3种timeout的设置:
connectionTimeout : socket建立链接的超时时间,Httpclient包中通过一个异步线程去创建socket链接,对应的超时控制。
timeoutInMilliseconds : socket read数据的超时时间, socket.setSoTimeout(timeout);
httpConnectionTimeout : 如果那个的是MultiThreadedHttpConnectionManager,对应的是从连接池获取链接的超时时间。
timeoutInMilliseconds就是你说的读取时间,它的定义是多长时间内如果无数据同步就认为超时。但如果是一个超大文件流,每隔1S给你来点数据,所以你这两个设置的时间,很快你的线程就会被一直RUNNING。来个几十请求,系统就差不多over了。
这里我们就需要给整个HttpClient请求做一个总的timeout时间控制,避免出现类似的情况。或者你也可以改写HttpClient关于输出流的实现,但不是很建议。因为HttpClient这样的设计也是有自己一定的理由,它为了链接共享,pooling,支持chunk协议等,就必须在一个请求关闭时把上一次未读完的流数据给消费光。避免对下一次请求的影响
类似的应用场景蛮多的,特别是在一些异步RPC调用中
哈,多谢支持。 项目中的需要,为了安全考虑,不然系统容易被人秒杀了。
这也是我同事发现的问题,我负责分析+编码。顺便研究了Linux wheel定时器调度算法,有空也可以实现个简单的。
发表评论
-
yugong QuickStart
2016-03-05 01:52 0几点说明 a. 数据迁移的方案可参见设计文档,oracl ... -
阿里巴巴开源项目: 阿里巴巴去Oracle数据迁移同步工具
2016-03-05 18:29 6551背景 08年左右,阿里巴巴开始尝试MySQL的相关 ... -
愚公performance
2016-03-02 17:29 0性能测试 全量测试 场景1 (单主键, ... -
yugong AdminGuide
2016-03-02 16:40 0环境要求 操作系统 数据库 迁移方案 部署 ... -
Tddl_hint
2014-01-27 13:52 0背景 工作原理 Hint格式 direct模 ... -
tddl5分库规则
2014-01-26 14:41 0背景 工作原理 构建语法树 元数据 基于 ... -
tddl5优化器
2014-01-22 15:12 0背景 工作原理 构建语法树 元数据 抽象语 ... -
Canal BinlogChange(mariadb5/10)
2014-01-20 17:25 4633背景 先前开源了一个 ... -
asynload quickstart
2013-10-08 22:49 0几点说明: 1. asyncload是做为一个j ... -
网友文档贡献
2013-09-18 15:50 01. Otter源代码解析系列 链接:http://e ... -
Manager配置介绍
2013-09-16 13:00 0通道配置说明 多种同步方式配置 a. 单向同步 ... -
canal&otter FAQ
2013-09-05 17:30 0常见问题 1. canal和 ... -
阿里巴巴开源项目:分布式数据库同步系统otter(解决中美异地机房)
2013-08-22 16:48 40479项目背景 阿里巴巴B2B公司,因为业务的特性 ... -
Otter AdminGuide
2013-08-19 11:06 0几点说明 otter系统自带了manager,所以简化了一 ... -
Otter高可用性
2013-08-17 23:41 0基本需求 网络不可靠,异地机房尤为明显. man ... -
Otter数据一致性
2013-08-17 23:39 0技术选型分析 需要处理一致性的业务场景: 多地修改 ( ... -
Otter扩展性
2013-08-17 22:20 0扩展性定义 按照实现不同,可分为两类: 数据处理自定 ... -
Otter双向回环控制
2013-08-17 21:37 0基本需求 支持mysql/oracle的异构数据库的双 ... -
Otter调度模型
2013-08-17 20:13 0背景 在介绍调度模型之前,首先了解一下otter系统要解 ... -
Otter Manager介绍
2013-08-16 11:16 0背景 otter4.0发布至 ...
相关推荐
如上所示,可以通过设置`HttpClient`的`Timeout`属性来指定请求超时时间。这是一个`TimeSpan`值,表示在接收到响应或完成请求之前等待的时间。默认值是100秒。 3. **临时覆盖超时**: 在某些情况下,可能需要为单个...
当网络出现问题时,如未设置socket timeout,JDBC连接可能会被长时间阻塞,类似于HttpClient未设置超时的情况。因此,设置合理的socket timeout至关重要,以防止CPU资源过度消耗和应用失去响应。 在应用与数据库间...
* setConnectTimeout(int timeout):设置连接到目标 URL 的等待时长,超过这个时间还没连上就抛出连接超时。 * setSocketTimeout(int timeout):设置连接到目标 URL 之后等待返回响应的时长,即超过这个时间就放弃...
Laravel Auth Timeout 是一个小型中间件包,用于检查用户是否在一段时间内发出了任何请求。 如果它们已达到空闲时间限制,则它们将在下一个请求时注销。 感谢 Brian Matovu 的。目录重定向AuthTimeout 外观 安装...
1. **Timeout 属性**:HttpClient有一个Timeout属性,可以用来设置整个请求过程的超时时间。这是一个整体超时,包括DNS解析、建立TCP连接、发送请求数据以及接收响应数据等所有步骤。如果在指定时间内没有完成这些...
同时,可以通过设置`Timeout`属性来控制请求的超时时间。 ```csharp httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置超时时间为30秒 ``` ### 7. 使用DelegatingHandler处理中间件逻辑 `HttpClient`允许...
4. **超时设置**:可能会提到如何设置请求超时,以防止因服务器响应过慢导致程序阻塞。 5. **异步编程**:由于Unity游戏引擎推荐使用异步操作以避免阻塞主线程,所以会涉及使用async/await关键字来实现非阻塞的网络...
本篇将详细探讨如何在RESTEasy中设置超时时间,以及相关的源码解析和工具使用。 首先,我们要明白在HTTP通信中设置超时的重要性。超时是为了避免客户端在等待服务器响应时无限期地阻塞,它为请求设定了一个预期的...
本文将深入探讨httpclient.jar包,以及它与code.jar包的关系,帮助开发者更好地理解和使用这两个组件。 httpclient.jar是Apache HttpClient库的核心组件,它提供了全面的HTTP协议支持,包括HTTP/1.1和部分HTTP/2。...
本文将深入探讨HttpClient的核心概念、主要功能以及如何有效地使用它。 HttpClient 4.2.5是HttpClient的一个稳定版本,它引入了许多改进和修复,提高了性能和稳定性。同时,HttpClient依赖于HttpCore库,这是Apache...
- **SPNEGO支持:** HttpClient支持SPNEGO认证机制,该机制常用于企业环境中。 - **GSS/Java Kerberos 设置:** 在Java环境中启用Kerberos认证通常需要进行一系列配置。 - **login.conf 文件:** 包含了Kerberos认证...
在本文中,我们将深入探讨HttpClient的核心概念、使用方法以及如何通过`httpclient.jar`进行实战应用。 首先,HttpClient的主要组件包括: 1. **HttpClient实例**:这是整个HTTP通信的核心,负责管理连接、请求和...
10. **性能优化**:通过配置连接超时、响应超时、线程池大小等参数,以及使用合适的连接管理策略,可以进一步优化HttpClient的性能。 在实际使用HttpClient时,需要根据项目需求选择合适的版本,理解其工作原理,...
本篇文章将深入探讨重新封装的HttpClient类,以及如何利用它进行高效且灵活的网络请求。 首先,我们来看一下`HttpClient`类的基本用法。原生的`HttpClient`类提供了发送GET、POST等不同HTTP方法请求的能力。例如,...
getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000); // 设置请求重试处理,用的是默认的重试处理:请求三次 getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new ...
本文将基于4.5.3版本的HttpClient官方API中文文档,深入探讨其核心概念、使用方法及常见应用场景。 一、HttpClient简介 HttpClient是一款高效的HTTP客户端库,它支持多种HTTP标准,包括HTTP/1.1、HTTP/2以及...
在本篇文章中,我们将深入探讨HttpClient的基本概念、功能以及其依赖的jar包。 HttpClient 4.2.1是文中提及的具体版本,它提供了丰富的功能,包括但不限于支持HTTP/1.1协议,支持连接管理,自动处理重定向,支持...