从手机说起
由于智能手机横行!!!所以垃圾软件横行!!!
做垃圾软件呢,又和做网站有一点小小的区别,由于软件装在用户的手机上,而且还可以 后台运行 ,所以只要安装了软件,就经常有很多连服务器的小动作比如,消息推送、心跳维持、当然了,还有恶意获取用户信息上传,肉鸡操控等等。
之前做网站,普通的网站一般也不会考虑并发过大的问题,比如小米的抢购、12306抢票等头疼的问题一般的网站也不会太多考虑,大不了在集群上多扩几台么。
现在情况有变,如果你的手机应用有一定的用户量,那么平时的压力就和网站时代的高峰压力相当了。如果你还是用之前的 Web 服务器,比如 Apache、 Tomcat 之类的,很容易就会遇到阻塞。
资源利用率
比如现在广泛应用的 Tomcat
,默认配置是 200 个 connection,如果同时有 500 个用户访问,那么200个用户会 1秒 的时候收到请求的响应,(收到后200线程被释放,处理剩下的300个请求),然后,200的用户等了两秒钟后,收到了响应。假设我们设置的服务超时时间为2秒,那么剩下100个,就会出现错误,请求失败。在这两秒种的时间,服务器仅处理了400个请求,还有100个请求在等待2秒后还被拒绝服务(超时),虽然说用户感觉到很慢,但实际上计算机的计算能力运用了不到 1% ,多余的性能并没有发挥出来。
聪明的你,肯定会想到,那我把默认最大线程数配大点不就行了吗,当然是 OK 的,比如配置到 500,那么这 500 个请求就不需要等待就可以马上响应了,此时,1秒钟处理了500个请求,CPU利用率肯定高出了之前的。但实际上如此盲目的增加通常会出现问题。
本质情况是,Tomcat,Apache之类的服务器处理一个请求,自身需要耗费比较多的资源。虽然本身也作了很多优化,但还是不太适合应用于大范围的通信,就拿上面那个请求来说,自己用纯 Java
写个多线程并发管理,会比服务挂在 Tomcat 上有好几个数量级的提升。 在这种场景下,你花好几台服务器作的一个 tomcat 集群也比不上一个比较好的并行处理请求的服务器。
C10K问题
C10K Problem ,也就是 Connect 10k = 1W 个连接下,目前现有的大半部分的应用都会无法处理,最常见的就是Web应用,上面也说到了这个问题,这些问题当然是早就存在早就知道了的,之所以现在才变得热门,当然就是移动互联网、微服务、云架构等模式需要一个应用去承载更多的通信量。
再比如聊天室、消息通知类似的应用,如果是使用长连接实现,16G内存情况下,一般一个长连接算内存占用2M(这个和使用的技术栈及模型有很大关系,比如Golang,nodejs等新兴语言原先就会优化的比较多,基于C的nginx也处理的不错),极限也就差不多能容纳10000个用户同时在线(保持长连接在线)。
对于长连接的应用场景,并发并不能解决问题,所以这里并不谈太多,个人认为像QQ微信这样的应用,一台机连索引都绘制不全,就别说维护了,如果你的业务并发量达到了10K以上,需要根据级别制定不同的算法,通常都是hash归类,固定配址等等,在这个级别上,不会有现成的如WEB框架之类的,但也会有些并发的较为基础的框架,你需要自己构建模型,通信规范等,才能更贴合业务需要。
又比如说邮件发送,我搞个促销活动,对我的100W注册用户发送个邮件通知
参考性能排行榜 https://www.techempower.com/benchmarks/
Java 并发编程
并发编程可以更大程序的利用计算机资源,避免性能浪费,常见的有并发编程框架也有很多,如 Netty
、 Vert.x
等,但如果你不懂一些 Java
的并发编程基础理念,实际上也很难看明白这些框架到底是怎么回事。
在 Java 里面,并发编程的工具基本上都放在 java.util.concurrent
包下面,
类 | 主要作用 |
---|---|
Runable | 实现此接口有让线程具有被 Run 的能力 |
Callable | 实际此接口让线程具有被 Call 的能力,并且可以有返回值,通过 Future 接口接收 |
ThreadPoolExecutor | 常用的线程池管理 |
ScheduledThreadPoolExecutor | 带有计划任务的线程池管理 |
Semaphore | 限制并发线程的数量 |
Exchanger | 可以使两个线程之间传输数据 |
CountDownLatch | 计数器的线程策略,支持同步计数等功能 |
CyclicBarrier | 周期线程策略,支持阶段性同步 |
Phaser | 多段的线程策略,可以控制线程的执行批次阶段 |
ExecutorCompletionService | 这个类具有边产生新任务、边处理完成任务的结果的能力 |
ExecutorService | 有执行各种线程的能力 |
ForkJoinPook | fork-join 式的任务池管理 管理 ForkJoinTask |
本想写点代码展示一下,但还是嫌麻烦(太懒了), 官方文档里面有 Demo,而且实际情况下,你不一定要精通它们,因为你会直接基于 Netty
之类的框架进行编写应用,但还是熟悉一下基础为好。
多线程编程要考虑的问题要比普通编程多很多,常见的有 阻塞与非阻塞 问题,线程排序 问题 ,各种异常等等,后续有空会另写文章展开。