非阻塞服务器需要注意的主要问题(译)

The main issue with non-blocking servers

 

非阻塞服务器有一个严重的问题,一些人甚至在没解决这个问题的背景下就开发自己的应用框架(比如Python的Tornado

当你使用非阻塞服务器的时候,你会获得出色的性能并且不需要担心可扩展性,然而同时你需要意识到一个问题:你的IO调用、网络系统调用也都是非阻塞的吗?很多人忽略了,他们使用的非阻塞服务器,其实是构建在阻塞库之上的。

在这篇文章里,我将深入对比多线程的服务器与非阻塞的服务器分别是如何工作的,以及你之所以需要在"使用的服务器"与"使用的库"在阻塞模式上保持一致的原因。

 

Non-blocking servers perform better

首先,我不会否认非阻塞服务器比阻塞服务器有更好的性能,尤其在那些有着数以万计的高并发用户的应用场景中。下面通过一些图片对说明这个问题,这些图片是WebFaction所测试的结果:

     A little holiday present: 10,000 reqs/sec with Nginx!

当他们从Apache向Nginx迁移时,发现:

Nginx每秒可以处理更多的请求:

nginx - req pr sec

Nginx比Apache使用更少的内存:

nginx - memory usage

真是令人吃惊的结果,那么为何不把非阻塞技术引入到你的 Python/Java/Ruby/PHP 框架里呢?

 

How blocking servers work

阻塞式服务器通常是基于多线程的,一个线程处理一个请求,它的工作方式可以现象化地表示为:

Threaded server

关于阻塞式服务器,有如下事实:

  • 处理高并发连接请求代价昂贵,服务器需要量产线程——线程并不便宜。
  • 库函数需要线程安全,这是多线程环境必需的。

 

How non-blocking servers work

非阻塞服务器不需要多线程,它通过一个IO循环及(异步)事件来处理请求,它的工作方式如下:

Non blocking server

关于非阻塞式服务器,有如下事实:

  • 处理高并发连接请求不是困难,这也是它被用于comet技术的重要原因
  • 在IO循环中的所有操作都必须是非阻塞,否则会因为你一个操作而阻断了整个循环
  • 不需要线程安全

 

Where Tornado (and others) go wrong

我以Tornado为例,但是其它的非阻塞式应用存在相同的问题:

Tornado使用了非阻塞式的服务器,但他们同时使用的库是阻塞式的,于是:

  • Tornado关于Mysql连接的库是阻塞的,这意味如果你的查询需要1s,那么你的loop循环就需要停下来1s等待查询的完成
  • 不要使用昂贵的系统调用,它会卡住整个循环
  • 同样,不要在循环中渲染模板,原因同上

就像我之前提过的,阻塞整个loop是致命的,因为此时你什么也做不了!

 

Conclusion

总之,非阻塞技术精巧且性能卓越,但要正确运用此技术,你必须使用同样是阻塞式的IO和Network调用,否则你将后患无穷!还有,请注意Python, Ruby, Java or PHP等这些语言缺省都是阻塞式的,所以当你同时使用非阻塞的服务器和这些语言其中之一的话,请务必当心!

Web.Java是一个高性能,轻量级的非阻塞服务器。 为了能更好的提高性能,Web.Java把HTTP服务区分应用和文件服务两种。 Web.Java 整体采用Reactor模式用来接收或响应HTTP请求(原理同Nginx)。 应用服务采用了Reactor来响应请求。 文件服务采用了Proactor模式,并搭配304状态使用,能极大的提高静态文件的相应速度,且不影响整体。 模板引擎 简单的标签:只需要记住{{}}标签用于输出变量,{%%}标签用于if,for 等操作。 可以继承的模版:页面的布局,HTML文件的复用等问题,通过模版继承机制可以得到解决。用{%extends xx%}关键字实现继承。 高性能:Web.Java会自动把Html文件,编成Java文件。应用到生产环境的时候,速度等同于Java的硬输出。且在DEBUG模式下,会动态的加载模板文件,而不需要重启进程。 灵活漂亮的URL 随便打开几个J2EE的网站,我就不想吐槽那个URL了。Web.Java使用正则表达式来配置URL,这样做可以提供足够强大和灵活的URL模式。比如像用“/Article/23”想获取文章的ID可以这样来配置URL HttpServer.setPATH("/Article/(\\d )",new ArticleHandler());   //ArticleHandler.java文件 get方法 public void get(String id){     //获取ID进行其他操作   ……   } 这样在ArticleHandler中对应的get或者post方法中就会获取相应的参数。当然,你可以任意的使用正则表达式来配置你的URL 简单易用的数据库操作 Options.DBURL = "jdbc:mysql://localhost:3306/test"; Options.DBDriver = "com.mysql.jdbc.Driver"; Options.DBUser = "root"; Options.DBPassword = "123456"; 配置好数据库信息后,可以直接在Handler中使用DB中的静态方法进行操作。 具体的操作在DB中有说明。当然如果你想,可以使用任何你想用的ORM。当然,希望你能直接使用SQL,不想解释为什么。 Hello World! 看名字就知道了。让我们开始使用Web.Java吧! 把源码包放到你的项目目录下面。 然后在main方法中加入 HttpServer.setPATH("/", new IndexHandler()); System.out.println("Listen 8080"); HttpServer.init(8080); IndexHandler.java public void get() {     this.writer("Hello World!"); } 现在Run it 浏览器打开就会看到你Writer的内容了。 标签:WebJava
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值