erl_0017 《硝烟中的erlang》 读书笔记004 “锁和阻塞”
如果某个进程需要持续地接收新任务,那么其在执行耗时过长的锁或者阻塞操作时,就会出现问题。
最为常见的例子之一就是:某个进程使用了TCP socket,阻塞在了接收新的连接或者等待消息上面。在执行此类阻塞操作时,消息会不受限制地堆积在消息队列中。 一个更为糟糕的例子是我曾经为lhttpc库的某个分支写的http连接池管理器。在大多数测试用例下,它都工作正常,我们甚至把连接的超时时间设置为10ms,以确保不会耗费太多的时间40。正常工作了几周后,该HTTP连接池导致了一次服务中断,原因是有个远程服务器down机了。 这次恶化背后的原因是:当远程服务器down机后,突然之间,所有的连接操作都至少要耗费10ms的时间,也就是连接超时时间。每秒大约有9,000个消息发给中心进程,通常每个消息的处理时间在5ms之内,这个超时的影响等同于每秒18,000个消息,情况变得失控。 我们的解决方案是,把进行HTTP连接的任务放到调用进程中,并加以限制,感觉仍像是管理器自己在做这件事一样。现在,阻塞操作分布到库的所有使用者之中,管理器要做的工作更少了,可以接受更多的请求。
当程序中有任何一个点,最终成为接收消息的中心点时,耗时的任务要尽可能从中移出。对于可以预见的过载41,增加更多的进程(它们或者处理阻塞的操作,或者在主进程阻塞时充当缓冲)往往是个不错的方法。 如果某些活动并没有内在的并发要求,那么这种方法会增加进程管理方面的复杂性,所以在这样做之前要确定自己确实有这个需要。 另外一种做法是,把阻塞任务变成异步的。如果场景适用,服务器可以启动一个进程来执行耗时(等待资源)的任务,赋予该进程一个唯一的令牌,把令牌和原始请求者保存起来。当资源可用时,这个进程会把令牌附带在消息中发送给服务器。服务器最终会得到这个消息,通过令牌匹配原始请求者,并发送回应,期间不会被其他请求所阻塞42。 这种做法要比使用多个进程的方法更晦涩一些,也很容易造成回调地狱(callback hell),但是使用的资源要更少些。
最新文章
- golang中string以及slice之间的一些问题
- Python小练习四
- JavaScript语言精粹学习笔记
- CameraFlash手电筒
- .net framework 4.0 从 GAC 卸载 程序集
- OpenCms 集成外部Solr Server
- Could not write to output file 'c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\xx'
- Web Service-- 使用 JDK 发布 WS
- 一些常用的JS函数
- WPF 3D:使用GeometryModel3D的BackMaterial
- win8和ubuntu双系统
- react-native —— 在Mac上配置React Native Android开发环境排坑总结
- SPI驱动调试感悟
- MySQL5.7基于binary log的主从复制
- Android Studio buildGrade文件注解
- [CodeForces 471A] MUH and Sticks
- 【CSS】元素样式
- GCC 多文件编辑
- k8s一点
- 数字和表达式(python)