互联网海量并发和海量数据处理背后涉及到高性能服务器的请求和响应,这里面如何处理成千上万的的用户请求?涉及到哪些技术?有哪些方向是可以进行优化的呢?本文总结了几种方案供参考。
一、多进程和多线程
- 多进程
在Linux的世界中,可以通过fork()方法来创建子进程,父进首先接收到用户请求,再自己创建子进程去处理用户的请求,这样每个用户的请求都得到了处理。
多进程的优点:
- 多进程编程思路和实现比较简单;
- 由于线程间地址空间相互隔离,所以多进程编程中单个进程的奔溃不会影响到其他线程,起到了线程隔离的效果。
- 充分发挥机器多核的价值,多个进程能并行跑在不同的CPU上;
多进程的缺点:
- 由于各个进程地址相互隔离,所以要实现进程中通信,需要借助进程中通信的相关机制;
- 创建和销毁进程的开销都比较大,所以频繁的进行进程的创建和销毁无疑会加重系统的负担;
- 多线程
由于多进程的创建和销毁开销过大,所以引入了多线程方式,一个进程下的多个线程他们共用相同的地址空间,所以创建的时候开销相对较小,更重要的是他们有了更方便的线程间通信方式。
多线程的优点:
- 创建线程的开销和负担相较进程更小;
- 多线程间共享相同的地址空间,能更好的实现线程间通信;
- 针对一些需要长时间执行的任务,利用多线程可以提高并行处理的性能;
多线程的缺点:
- 多线程通信使用不当,存在线程安全问题,存在数据不一致的问题;
- 一个进程内可能存在多个线程,单个线程的奔溃,可能会引发进程的奔溃,所以安全隔离级别没有进程高;
二、事件驱动
事件驱动编程中2个最重要的角色为:
- 事件:就是在主线程中触发另个线程或逻辑处理的事件,一般事件可能会和IO操作相关,比如网络收发报文、磁盘读写文件等;
- 事件处理函数:就是获取到这个事件后,如何处理这个事件的逻辑;
一般的事件驱动编程模型为:
while(true){
event = getEvent();//获取到事件
result = handler(event);//处理事件
}
以上这种事件驱动的处理模型存在问题,因为getEvent()方法只能获取一种事件,handler(event)也只能处理一种事件,就是如何处理多种事件呢?
这个可以选择IO多路复用来解决,IO多路复用是通过单独一个dispatcher来监控事件,如果获取到了某个事件,就将该事件转发到对应的handler来进行处理,这也是Linux中epoll实现的主要思路。
三、异步和回调方式
同步调用的逻辑简单、易实现,在开发前期可以通过这样的方式迅速实现功能,进行功能验证,但是在生产环境面对高并发情况,同步调用的效率比较低下,这是由于工作现在会阻塞主线程的执行。有没有一种更好的方案来解决高并发场景?
一种更好的方案是通过异步和回调方式来实现,在主线程中调用工作线程时,采用的是一种异步调用的方式,这样就不会阻塞主线程的执行,如果异步线程还有返回值的话,可以在异步方法中传入回调函数,这样在异步线程执行完成后会自动调用回调函数。
一般的编程模式:
void handler(request){
getInfoAsync(request, callBack())
}
getInfoAsync(request, callBack(){
//异步处理
callBack(returnInfo);//调用回调函数
}
callBack(returnInfo){
//回调处理
}
在Java中可以通过CompletableFuture框架来实现异步和回调。
协程
todo