Dubbo调用超时那些事儿
其实之前很早就看过Dubbo源码中关于超时这部分的处理逻辑,但是源码那事没有记录下来,最近在某脉上看到有人问了这个问题,源码那事想着再回顾一下。源码那事开始从dubbo的源码那事请求开始,看看dubbo(2.6.6)在超时这块是源码那事怎么处理的:
com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int)@Overridepublic ResponseFuture request(Object request, int timeout) throws RemotingException { if (closed) { throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");}// create request.Request req = new Request();req.setVersion(Version.getProtocolVersion());req.setTwoWay(true);req.setData(request);DefaultFuture future = new DefaultFuture(channel, req, timeout);try { channel.send(req);} catch (RemotingException e) { future.cancel();throw e;}return future;}DefaultFuture从返回值ResponseFuture类型可以看出,这是源码那事一个异步方法(不等同于Dubbo的异步调用)。那么调用超时的源码那事关键可以从ResponseFuture来看:
public interface ResponseFuture { Object get() throws RemotingException;Object get(int timeoutInMillis) throws RemotingException;void setCallback(ResponseCallback callback);boolean isDone();}可以看到这是一个接口,从request方法可以得知实现类是源码那事DefaultFuture,从构造函数入手:
public DefaultFuture(Channel channel,源码那事 Request request, int timeout) { this.channel = channel;this.request = request;this.id = request.getId();this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);// put into waiting map.FUTURES.put(id, this);CHANNELS.put(id, channel);}可以得知每一个DefaultFuture都有一个id,并且等于requestId,timeout是补码变源码算法从url中获取的配置,没有时默认ms。
从代码的注释可以看到FUTURES这个map应该就是关键,是一个waiting map。
DefaultFuture中还有一个方法:
public static void received(Channel channel, Response response) { try { DefaultFuture future = FUTURES.remove(response.getId());if (future != null) { future.doReceived(response);} else { logger.warn("The timeout response finally returned at "+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))+ ", response " + response+ (channel == null ? "" : ", channel: " + channel.getLocalAddress()+ " -> " + channel.getRemoteAddress()));}} finally { CHANNELS.remove(response.getId());}}可以看到调用的地方为:
com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#received
@Overridepublic void received(Channel channel, Object message) throws RemotingException { //省略一些代码} else if (message instanceof Response) { handleResponse(channel, (Response) message);//省略一些代码}}com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleResponse
static void handleResponse(Channel channel, Response response) throws RemotingException { if (response != null && !response.isHeartbeat()) { DefaultFuture.received(channel, response);}}回到DefaultFuture.received,可以看到通过Response id从FUTURES中拿了一个DefaultFuture出来,然后调用了doReceived方法,也就是说Response id和Request id 相同。结下来看看doReceived做了什么:
private void doReceived(Response res) { lock.lock();try { response = res;if (done != null) { done.signal();}} finally { lock.unlock();}if (callback != null) { invokeCallback(callback);}}首先是加锁,然后通过唤醒了阻塞在Condition上的线程。看看什么地方会阻塞在done这个条件上:
@Overridepublic Object get(int timeout) throws RemotingException { if (timeout <= 0) { timeout = Constants.DEFAULT_TIMEOUT;}if (!isDone()) { long start = System.currentTimeMillis();lock.lock();try { while (!isDone()) { done.await(timeout, TimeUnit.MILLISECONDS);if (isDone() || System.currentTimeMillis() - start > timeout) { break;}}} catch (InterruptedException e) { throw new RuntimeException(e);} finally { lock.unlock();}if (!isDone()) { throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));}}return returnFromResponse();}是get方法,get方法确实在request请求后被调用:
(Result) currentClient.request(inv, timeout).get()可以看到get方法的大致逻辑为,先获取锁,然后循环判断isDone,并阻塞等到条件,当条件超时,如果任务完成,源码相加的过程或者超过timeout结束循环,接着判断isDone,如果超时抛出TimeoutException。并且通过sent(request请求时间)是否>0()来判断是clientSide还是serverSide超时。
isDone逻辑如下:
@Overridepublic boolean isDone() { return response != null;}如果是正常Response,也有可能是超时的现象,可以看到get方法最后调用了一个函数:
public interface ResponseFuture { Object get() throws RemotingException;Object get(int timeoutInMillis) throws RemotingException;void setCallback(ResponseCallback callback);boolean isDone();}0TIMEOUT SIDESERVER_TIMEOUT(服务端超时): 这个就是正常的我们消费端请求一个RPC接口,服务端由于性能等一些原因处理时间超过了timeout配置时间。
CLIENT_TIMEOUT:我们可以看到是通过sent(上面有说sent>0)这个来判断是否clientTimeout,那么这个sent什么时候改变呢?就在发送请求的地方:
public interface ResponseFuture { Object get() throws RemotingException;Object get(int timeoutInMillis) throws RemotingException;void setCallback(ResponseCallback callback);boolean isDone();}1也就是说handler.sent一旦调用成功返回,那么就不算clientSide Timeout了。那么CLIENT_TIMEOUT大概率就是由于client端网络,系统等原因超时。
原文:/post/开源运动发展史与开源许可证(BSD、GPL、Apache、活动报名源码4.2.5MIT、木兰(中国))的那些事儿
开源运动始于上世纪年代末期,随着Unix系统的诞生,源代码的开放成为了可能。Unix的发明者之一肯·汤普森,为了提高编程效率,设计了C语言。随后,Unix逐渐商业化,自由软件的概念随之诞生。理查德·斯托曼于年发起自由软件运动,创建了GNU项目,并引入了Copyleft的概念,通过GPL(GNU通用公共许可证)来保护软件的自由使用和分发。年,Linux的网空包网源码诞生标志着开源软件进入了新的阶段,它遵循了GPL许可,并于年加入GNU项目。开放源代码(Open Source)的概念在年由埃里克·雷蒙德提出,他倡导共享源代码可以产生更好的结果,促使了开放源代码促进会(OSI)的成立,以协调不同的开源许可标准,使得商业公司也能使用开源软件,而无需公开源代码。
开源许可证大致分为两大类:Copyleft(如GPL)和Permissive(如MIT、BSD)。Copyleft许可证要求任何基于该许可证软件的修改和衍生作品也必须遵循相同的许可证,以保持代码的自由性和可访问性。Permissive许可证则给予用户更大的灵活性,允许软件被自由地使用、修改和分发,但不强制要求开源或提供源代码。常见的Copyleft许可证有GPL,而MIT、BSD和Apache许可证属于Permissive类型。
在中国互联网出海背景下,开源合规成为重要议题。无论是使用开源代码还是计划将自己的软件以开源方式发布,都需要了解开源软件及其许可证的相关知识。中国开放原子基金会和木兰(中国)开源许可证的出现,旨在为中国开发者提供一个既符合国际标准又适应当地法律和文化背景的开源许可选择。木兰许可证的引入,为解决中国开发者在使用开源代码时遇到的特定法律问题提供了解决方案,同时满足了国际开源社区的需求,促进了全球开源生态的发展。
我需要 《Linux那些事儿之我是USB》,这种高清教材百度网盘资料有人分享吗
我这里有您想要的资源,通过百度网盘免费分享给您:/s/1uj3zg8VxmA-xh1FQZRklog
提取码:本书基于2.6.内核,对USB子系统的大部分源代码逐行进行分析,系统地阐释了Linux内核中USB子系统是如何运转的,子系统内部的各个模块之间是如何互相协作互相配合的。
本书使用幽默诙谐的笔调对Linux内核中的USB子系统源代码进行了分析,形象且详尽地介绍了USB在Linux中的实现。本书从U盘、Hub、USB Core直到主机控制器覆盖了USB实现的方方面面,被一些网友誉为USB开发的“圣经”。
操作系统的那些事儿——表驱动法
在年年末,出于个人兴趣,我启动了一个小型操作系统项目。由于学业压力,我完成了分页和VFS功能后就暂时搁置了。为了跟踪开发进度,我在GitHub上分享了源码链接:
经过长时间的积累,代码量逐渐增多,被划分为不同的文件夹,如boot文件夹包含了启动记录和从实模式转为保护模式的代码,而kernel文件夹则包含了核心功能,特别是kernel/dev,我亲手编写的键盘与中断控制器(PIC)驱动就在这里。
在后续的文章中,我计划详细讲述整个项目的内容,但本文将聚焦在交互模块——kernel/shell.c,这是一个用于调试的命令行。我添加了类似于Linux的cat和ls命令,以及用于检查虚拟机端口状态的floppy命令,尽管软盘驱动在位环境下复杂,但这些命令并未单独存储,而是整合在单个文件中。
起初,我用if else结构处理调试指令,但随着指令增多,管理变得困难,我开始采用抽象,将所有命令封装为一个struct,如一个函数指针handle,指向执行函数。在shell_main()中,通过for循环和strcmp判断用户输入,这种实现方式后来被我认识到是表驱动法。
表驱动法在我的操作系统中也被广泛应用,例如在kernel/dev/device.c中,我使用表驱动法对系统设备进行了抽象。通过write、read、open、close和ioctl等接口,我实现了对设备功能的封装,无需直接调用设备驱动,而是通过dev_**的方式进行操作。
回顾过去,虽然我的操作系统项目暂时停滞,但通过分享这些原理和机制,我希望能重新唤起对它的兴趣。通过连载文章的形式,我将逐步揭示这个系统的深层运作。
ç¼ç¨å¦ä¹ å¿ çç书ï¼
ä¸ããWebå端å¼åæä½³å®è·µãè¿æ¬ä¹¦æ¯å端å¼åé¢åçç»å ¸ä¹ä½ï¼æ¯ä¸æ¬æå®å端åºæ¬åï¼è§èæ们å端代ç çå®è·µæ§ä¹¦ç±ãæ¬ä¹¦ä¸»è¦è®²è§£äºHTMLãCSSãJavascript以å移å¨ç«¯å¼åçæä½³å®è·µæ¹æ¡ï¼è½å¤å¯¹ç¼ºä¹è¯å¥½æ导çå¼åè 产çå¾å¤§ç帮å©ãéè¿é 读æ¬ä¹¦æ们å¯ä»¥ææ¡å¦ä½ç¼åé«å¯è¯»æ§ãé«ç»´æ¤æ§ãé«æ§è½çHTMLãCSS以åJavascriptã
äºããCSSé£äºäºå¿ã
å 容ä»ç»ï¼ãCSSé£äºäºå¿ãæ¯å¹´çµåå·¥ä¸åºç社åºççå¾ä¹¦ï¼ä½è æ¯æå°å¿ã该书éè¿å¯¹CSSæå·§å®ä¾è¿è¡è®²è§£ï¼æµ å ¥æ·±å°åæäºCSSç¸å ³ç¥è¯ã
éè¿é¡µé¢ä¸çæåãå¾çãè¡¨æ ¼ã表åç常è§å ç´ çå¤çååç§é¡µé¢å¸å±æ¹å¼ç使ç¨ï¼ä½¿è¯»è è½æ·±å ¥äºè§£å°å¦ä½å¨é¡µé¢ä¸æ´å¥½å°è¿ç¨CSSå¸å±ãå°¤å ¶æ¯å¨é¡µé¢å¸å±çé¨åä¸ï¼å ¨é¢åæäºå¤ç§å¸å±æ¹å¼ï¼çéå解äºä¸¤åçé«åä¸åçé«çå ç§æ¹å¼ï¼å¹¶ç¸åºè¯´æäºçé«å¸å±çä¼ç¼ºç¹ã
ä¸ããCSSæå¨æåã
å 容ä»ç»ï¼ãCSSæå¨æåãéè¿è¯¸å¤å®ä¾ï¼è¯¦ç»è®²è§£äºå¦ä½åå°ä» å¨ä¸å¤å»ºç«æ ·å¼è¡¨å°±è½å建æä¿®æ¹æ´ä¸ªç½ç«çå¤è§ï¼ä»¥åå¦ä½å¾å°htmlåä¸è½åçæ´ä¸°å¯ç表ç°ææãåæ¶å±ç¤ºäºå¦ä½éµå¾ªcssææ°è§èï¼css2åcss2.1ï¼å°å±å æ ·å¼è¡¨çæ¹æ¹é¢é¢åºç¨äºå®è·µã
åããJavaScript æ ååèæç¨ãé®ä¸å³°
å 容ä»ç»ï¼é®ä¸å³° æ¬ä¹¦å ¨é¢ä»ç» JavaScript æ ¸å¿è¯æ³ï¼ä»æç®åçå¼å§è®²èµ·ï¼å¾ªåºæ¸è¿ãç±æµ å ¥æ·±ï¼åæ±æ¸ æ°ææãææç« èé½å¸¦æ大éç代ç å®ä¾ï¼ä¾¿äºç解å模仿ï¼å¯ä»¥ç¨å°å®é 项ç®ä¸ï¼å³å¦å³ç¨ã æ¬ä¹¦éååå¦è å½ä½JavaScriptè¯è¨çå ¥é¨æç¨ï¼ä¹éåå½ä½æ¥å¸¸ä½¿ç¨çåèæåã
äºãJavaScripté«çº§ç¨åºè®¾è®¡ç¬¬ä¸ç
å 容ä»ç»ï¼ãå ¨ä¹¦ä»JavaScript è¯è¨å®ç°çå个ç»æé¨åââè¯è¨æ ¸å¿ãDOMãBOMãäºä»¶æ¨¡å讲起ï¼æ·±å ¥æµ åºå°æ¢è®¨äºé¢å对象ç¼ç¨ãAjax ä¸Comet æå¡å¨ç«¯éä¿¡ï¼HTML5 表åãåªä½ãCanvasï¼å æ¬WebGLï¼åWeb Workersãå°çå®ä½ãè·¨ææ¡£ä¼ éæ¶æ¯ã客æ·ç«¯åå¨ï¼å æ¬IndexedDBï¼çæ°APIï¼è¿ä»ç»äºç¦»çº¿åºç¨åä¸ç»´æ¤ãæ§è½ãé¨ç½²ç¸å ³çæä½³å¼åå®è·µã
å ãéå©çjquery
å 容ä»ç»ï¼ãéå©çjQuery(第2ç)ã循åºæ¸è¿å°å¯¹jQueryçåç§å½æ°åæ¹æ³è°ç¨è¿è¡äºä»ç»ï¼è¯»è å¯ä»¥ç³»ç»å°ææ¡jQueryçéæ©å¨ãDOMæä½ãäºä»¶åå¨ç»ãAJAXåºç¨ãæ件ãjQuery MobileãjQueryå个çæ¬ååãjQueryæ§è½ä¼ååæå·§çç¥è¯ç¹ï¼å¹¶ç»åæ¯ä¸ªç« èåé¢çæ¡ä¾æ¼ç¤ºè¿è¡ç»ä¹ ï¼è¾¾å°ææ¡æ ¸å¿ç¥è¯ç¹çç®çã
ä¸ãHTTPæå¨æå
å 容ä»ç»ï¼ãHTTPæå¨æåãç±å¤å°å©æèï¼ãHTTPæå¨æåã详ç»è§£éäºå¦ä½ç¨HTTPæ¥å¼ååºäºWebçåºç¨ç¨åºï¼æ ¸å¿ç[å ç¹ç½åè®®ï¼å¦ä½ä¸æ¶ææ建å交äºï¼å¦ä½æ£ç¡®å®ç°å ç¹ç½å®¢æ·åæå¡å¨çã
ãHTTPæå¨æåãçä¸å¿å 容æ¯HTTPï¼æ¬è´¨æ¯ç解Webçå·¥ä½åçï¼ä»¥åå¦ä½å°è¿äºç¥è¯åºç¨å°Webç¼ç¨å管çä¹ä¸ï¼ä¸»è¦æ¶µçHTTPçææ¯è¿ä½æ¹å¼ã产çå¨æºãæ§è½åç®æ 以åä¸äºç¸å ³ææ¯é®é¢ã ãHTTPæå¨æåãéåæææ³äºè§£HTTPåWebåºå±ç»æç人é 读ã
å «ãé«æ§è½ç½ç«å»ºè®¾æå
å 容ä»ç»ï¼ãé«æ§è½ç½ç«å»ºè®¾æåãç»åWeb2.0以æ¥Webå¼åé¢åçææ°å½¢å¿åç¹ç¹ï¼ä»ç»äºç½ç«æ§è½é®é¢çç°ç¶ã产ççåå ï¼ä»¥åæ¹åæ解å³æ§è½é®é¢çååãææ¯æå·§åæä½³å®è·µãéç¹å ³æ³¨ç½é¡µçè¡ä¸ºç¹å¾ï¼ééä¼åAjaxãCSSãJavaScriptãFlashåå¾çå¤ççè¦ç´ çææ¯ï¼å ¨é¢æ¶µçæµè§å¨ç«¯æ§è½é®é¢çæ¹æ¹é¢é¢ã
2024-11-23 11:45
2024-11-23 11:39
2024-11-23 10:50
2024-11-23 10:37
2024-11-23 09:24