Python 异步 IO 的未来(从 Web 后端开发的角度) 已翻译 100%

magicoding 投递于 2014/12/02 23:15 (共 25 段, 翻译完成于 12-07)
阅读 19545
收藏 161
10
加载中

免责声明:我是一个工程师,拥有10年以上的 WEB 后端开发经验,大部分职业生涯都在编写 Python代码。所以本文大部分文字描述可能跟软件开发的其他领域无关,同样的,也跟使用 JVM 或 CLR 的开发者无关,他们只是用不同的方式解决问题。

开发Web应用程序看起来与我们10年前做的有很大的不同。现在,我们用微服务建立的一切。它彻底改变了我们的应用程序的架构。

2014年,如果你还在构建完整巨大的 web 应用程序,你需要改变这一行为,否则很快会被解雇

虽然我们的应用程序的设计发生了很大变化,但是我们的工具没有。这里我要介绍未来我会如何编写微服务。但是,首先,让我们来看看我们有什么。

jk409
jk409
翻译于 2014/12/03 13:17
2

全局解释锁

对于声名狼籍的Python GIL,Python的支持者说的比较多的是其他的脚本语言也有(Ruby,Perl,Node.js,还有一些)。对于不好的语言解释器的设计,这是圣战的源头,但这对于web应用从来不是问题。我们总是以来许多进程共享一个数据库。

在微服务面前,全局解释锁更加不是问题了。在大多数情况下,单个微服务甚至比十年前的典型web应用还小。尽管很小,它每秒也可以处理大量的请求,大多数是因为它针对查询的类型,进行了高度的定制化和很好的调整。

而当构建的微服务需要等待其他服务回复的时间时,这开始成为一个问题。好戏由此开场。。。

Ley
Ley
翻译于 2014/12/03 23:23
1

“异步I / O,或非阻塞I/ O是输入/输出进程的一种形式,它允许其他进程继续在传输完成之前。”- 维基百科
 

任何异步库基本是从左侧到右侧的流程来调整代码的:

同步(左)与异步(右)请求进程对比图

jk409
jk409
翻译于 2014/12/03 14:00
1

Python的异步I/O支持是相当的好。有一堆库可以做这个工作(Twisted, Tornado, Gevent, Eventlet,这里仅列举几个)。每个库都支持很多协议。你可以使用MySQL, Mongo, PostgreSQL, Redis, Memcache, ElasticSearch...,几乎每个DB,和许多其他得服务。一些奇异的协议,像SSH或者Beanstalk只在几个库中支持。不过这些都不是问题,写另一个协议或从一个I/O框架移植到另一个也不是很难。

当然,每一个I/O库都支持客户端和服务端HTTP。想必,这就是为什么HTTP是最常见的用于微服务之间通信的协议。不过大多数框架也支持各种其他协议(msgpack-rpc, thrift, zeromq, ice,这里仅列举几个)。

开源中国七里香
开源中国七里香
翻译于 2014/12/04 19:31
1

有很多框架存在,彼此在不同协议的使用便捷性和其他种类的并发抽象上的有所不同。当然对不同协议的支持已经变得越来越流行。直到Twisted在2002年发布,这种状况才有所改变。是的,即使当python支持了yield和stacklessgreenlets出现,便捷性确实大大增加了,但是这也仅仅是增加一点点的便捷性。真正的改变是在2002年。

但是有些事情是大多数Python框架的弱项。当你在一个线程中操控很多个客户端的请求时,你有可能把它们管道进单个连接中。也就是说,如果你在前端有三个GET请求,你可能向MySQL数据库发送三次请求,但不等待回复。一旦收到(数据库)的数据就尽快回复客户端。就像上面图中表示的,但是使用了单个DB连接。大多数python框架现在,在请求开始时从连接池中拉取一个连接,在请求结束时释放连接,这样高效的保证连接数目与同时请求数目相等。

Ev4n
Ev4n
翻译于 2014/12/05 09:19
1

对于多数数据库来说,成千上万个连接仍然是个问题。即使的典型的Sharding也无济于事,因为对每个shard来说也是相同数目的连接。很多用户采用了特殊的微服务(microservice)。这不仅仅是数据库的问题,许多微服务(microservice)也同样遇到这样问题。

幸好asyncio架构允许更容易的构建流水线(pipelining),所以越来越多的asyncio协议采用这种技术。不幸的是连接代价巨大的数据库(比如MySQL和PostgreSQL)使用了不支持(该技术)的C库,而且没有人有足够的重视来写一个更好的。

Ev4n
Ev4n
翻译于 2014/12/05 09:53
1

使用像Resque一样的发布-订阅

当前,许多工程团队围绕着发布-订阅来构建微服务(microservices)架构。比如,他们运用RabbitMQ或者其竞争者之一的产品将所有内容发布成消息(message)。他们相信这是简化他们的建构:

  1. 单总线(Single Bus),无须再考虑这个

  2. 能够无需等待回复即可发布消息。不需要任何异步库即可高效的获取异步I/O

当部分工程师们以为这就是答案的时候,我认为这不适合普遍的情况。

我认为将我的设计决策限制在使用特定插件及特定的消息调度算法不会解决我的所有网络问题。
Ev4n
Ev4n
翻译于 2014/12/05 13:52
1

ZeromqNanomsg 方式

另一个颇具魅力的微服务架构是Zeromq。如果你对它不熟悉,你应该尽快了解它。Zeromq只不过是巧合的使用MQ(消息队列)作为后缀,毕竟它不像 RabbitMQKafka以及其他的那样拥有中心消息队列。它是以socket形式工作在steroids。也就是说,它看起来就像常规的socket,确实会自动发送消息(分割TCP数据流为帧),重新连接,点对点平衡加载等等。

在 Zeromq 世界里有三种方式供你的服务于其他连接:

  1. 发布-订阅,工作方式基本上和其他发布-订阅应用程序相同

  2. 请求-回复,基本与RPC工作方式相同

  3. Push-Pull,请求却不需要回复,或者发布-订阅发送消息到单一接收端(基于轮叫)

Ev4n
Ev4n
翻译于 2014/12/05 14:22
1

Nanomsg 做到了更多事情,它不仅支持上面提到的所有方式,而且增加了更多的通信模式(单就nanomsg而言):

  1. 监督者-应答者(Surveyor-respondent),允许向多点发送请求而且接收来至所有的请求

  2. 总线(Bus),允许向任何点发送消息

更多的是:nanomsg的前景在于通信模式是插件式的,也就是说,在未来更多的通信模式会被增加到库中。

我相信更多的通信模式会出现,而使用发布-订阅或者HTTP难逃厄运

像nanomsg和zeromq作为脚本语言的优势是:它们在一个单独的线程中操控I/O。所以当你使用python做一些事情操控全局解释器锁(GIL)时,你的zeromq线程保持你的连接,清空消息缓冲器,接收和建立连接等等。

Ev4n
Ev4n
翻译于 2014/12/05 14:49
1

真实世界中的微服务

当聪明的黑客们创建了像 zeromq 、 nanomsg 和发布-订阅总线( publish-subscribe buses )这样优秀的项目的时候,实干的工程师们却仍然使用旧的技术干活。

到目前为止我还没有看到使用 zeromq 作为数据库存取通讯方式的数据库。嗯,现在是有很少一些使用了 zeromq 的开源服务。基本上所有现代的数据库在通讯方式的实现上目前分成了以下两个阵营:

  1. 创建并使用自身协议

  2. 使用 HTTP 协议

在这个方面数据库算是个比较突出的例子。另外的例子比如 Docker , Docker 使用了基于 unix sockets 的 HTTP 协议作为其通讯协议,然而,当她需要使用全双工流( full-duplex streams )来替代请求-回应( request-reply )模式的时候,就只能很不优雅地打破了其使用的协议的语义( protocol semantics )。

magicoding
magicoding
翻译于 2014/12/05 23:17
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(26)

FBWFBI
FBWFBI

引用来自“Raymin”的评论

Java 没有 GIL
JavaScript 没有 GIL
Lua 没有 GIL
Tcl 没有 GIL
并且这些语言都不怕复制粘贴
还有补充的没有?

引用来自“FBWFBI”的评论

Java 没的说,JVM毕竟是商业产品, tcl就懒得说了,没见几个人用,而至于你说的这些 JavaScript 、Lua这些提供线程么? 是直接提供真正的线程(操作系统级别的线程,非用户态的协程)?既然线程都没有,那还谈什么线程安全,说个毛的GIL

引用来自“Raymin”的评论

呵呵!

引用来自“FBWFBI”的评论

呵呵个蛋,你连javascript是单线程的都不知道,也来拿比个蛋!!nodejs里面的一个v8的实例也都是单线程的逻辑,当然不需要GIL。就像前面一个兄台说的,GIL只是CPython的实现,又不是语言限制,你除了整天拿语言来打嘴仗,又有多少真才实学,有本事自己实现一个无GIL版的python解释器呗,不行就少出来丢!

引用来自“Raymin”的评论

js 语言层面以前是没有线程的概念,但不代表js解释器不支持多线程,何况 js 现在有了 worker 的概念。 Python 我也是比较喜欢的,但语言就是个工具,没必要因为语言的争论而失态。
抱歉,兄台,之前说话多有不妥,现在想想多有惭愧,搞技术的确实要理智一点,不能太情绪化,这里向你道歉了...
Raymin
Raymin

引用来自“Raymin”的评论

Java 没有 GIL
JavaScript 没有 GIL
Lua 没有 GIL
Tcl 没有 GIL
并且这些语言都不怕复制粘贴
还有补充的没有?

引用来自“FBWFBI”的评论

Java 没的说,JVM毕竟是商业产品, tcl就懒得说了,没见几个人用,而至于你说的这些 JavaScript 、Lua这些提供线程么? 是直接提供真正的线程(操作系统级别的线程,非用户态的协程)?既然线程都没有,那还谈什么线程安全,说个毛的GIL

引用来自“Raymin”的评论

呵呵!

引用来自“FBWFBI”的评论

呵呵个蛋,你连javascript是单线程的都不知道,也来拿比个蛋!!nodejs里面的一个v8的实例也都是单线程的逻辑,当然不需要GIL。就像前面一个兄台说的,GIL只是CPython的实现,又不是语言限制,你除了整天拿语言来打嘴仗,又有多少真才实学,有本事自己实现一个无GIL版的python解释器呗,不行就少出来丢!
js 语言层面以前是没有线程的概念,但不代表js解释器不支持多线程,何况 js 现在有了 worker 的概念。 Python 我也是比较喜欢的,但语言就是个工具,没必要因为语言的争论而失态。
FBWFBI
FBWFBI

引用来自“Raymin”的评论

Java 没有 GIL
JavaScript 没有 GIL
Lua 没有 GIL
Tcl 没有 GIL
并且这些语言都不怕复制粘贴
还有补充的没有?

引用来自“FBWFBI”的评论

Java 没的说,JVM毕竟是商业产品, tcl就懒得说了,没见几个人用,而至于你说的这些 JavaScript 、Lua这些提供线程么? 是直接提供真正的线程(操作系统级别的线程,非用户态的协程)?既然线程都没有,那还谈什么线程安全,说个毛的GIL

引用来自“Raymin”的评论

呵呵!
呵呵个蛋,你连javascript是单线程的都不知道,也来拿比个蛋!!nodejs里面的一个v8的实例也都是单线程的逻辑,当然不需要GIL。就像前面一个兄台说的,GIL只是CPython的实现,又不是语言限制,你除了整天拿语言来打嘴仗,又有多少真才实学,有本事自己实现一个无GIL版的python解释器呗,不行就少出来丢!
Raymin
Raymin

引用来自“Raymin”的评论

Java 没有 GIL
JavaScript 没有 GIL
Lua 没有 GIL
Tcl 没有 GIL
并且这些语言都不怕复制粘贴
还有补充的没有?

引用来自“FBWFBI”的评论

Java 没的说,JVM毕竟是商业产品, tcl就懒得说了,没见几个人用,而至于你说的这些 JavaScript 、Lua这些提供线程么? 是直接提供真正的线程(操作系统级别的线程,非用户态的协程)?既然线程都没有,那还谈什么线程安全,说个毛的GIL
呵呵!
FBWFBI
FBWFBI

引用来自“Raymin”的评论

Java 没有 GIL
JavaScript 没有 GIL
Lua 没有 GIL
Tcl 没有 GIL
并且这些语言都不怕复制粘贴
还有补充的没有?
Java 没的说,JVM毕竟是商业产品, tcl就懒得说了,没见几个人用,而至于你说的这些 JavaScript 、Lua这些提供线程么? 是直接提供真正的线程(操作系统级别的线程,非用户态的协程)?既然线程都没有,那还谈什么线程安全,说个毛的GIL
asdfsx
asdfsx
解决不了GIL,线程就是个样子货,不用进程始终发挥不了多核cpu的性能。再怎么异步都扯淡。
目前看起来唯一能解救python的只有pypy下的stm了~~~
但是我讨厌引入第三方的实现啊~~~
道道
道道
KAN BU DONG
s
sam.yang

引用来自“qijingq”的评论

我阅读能力有问题,看得不是很懂。

引用来自“sunday12345”的评论

me 2

引用来自“叫啥名字好呢”的评论

me 3

引用来自“小乐食客”的评论

me 4

引用来自“漫画三毛”的评论

me5
me 6
DarkAngel
DarkAngel

引用来自“qijingq”的评论

我阅读能力有问题,看得不是很懂。

引用来自“sunday12345”的评论

me 2

引用来自“叫啥名字好呢”的评论

me 3

引用来自“小乐食客”的评论

me 4

引用来自“漫画三毛”的评论

me5
完全没读懂。。。。。。
句龙胤
句龙胤
异步核心其实非常简单,首先,网络服务都是同步的,没有什么异步。异步其实就是把一个回复分成两个回,这样可以不会被阻塞。

就像调度一样,当执行I/O指令时,马上切换到其他线程,等I/O设备回复后,再切换回来
返回顶部
顶部