分享 [手册更新中] 异步小轮子 nyara

luikore · 2013年06月20日 · 最后由 luikore 回复于 2014年01月03日 · 9186 次阅读
本帖已被管理员设置为精华贴

https://github.com/luikore/nyara

大致功能是相当于 eventmachine + thin + rack + sinatra + 0.5 个 padrino

弄了一周多, 差不多 5k 行了, 功能测试文档都未完整先扔了个 pre 占坑, 仅限 OSX/BSD/Linux 和 Ruby 2.0+, 暂时只对跑 hello world 有信心...

require 'nyara'

get '/' do
  send_string 'hello world'
end

hello world 在我的机器上

ab -c 20 -n 8000 http://127.0.0.1:3000/

可以有 6k-7k 的 TPS (默认响应带了一些 nosniff 之类的 header, 如果去掉是能上万的...), 等功能完备后再整 real world benchmark.


6-27 更新 manual https://github.com/luikore/nyara/wiki/Manual

2014-1-3 更新 obsolete 不更新了

别优化半天,才和 Erlang 不优化一样快

http://www.erlang-factory.com/upload/presentations/658/jlouis-euc-2012.pdf

Some libraries are extremely complex type-wise After 2 months of tuning on and off I went back to Erlang I Unoptimized Erlang version as fast as Combinatorrent in practice

限制 ruby 版本跟平台是因为用到了某些高级特性(比如 copy-on-write 之类的)的原因么?

#1 楼 @bhuztez 有可能哦, 有空写个同样功能的 mochiweb 比较下

其实也用了一些现成的东西, 例如 joyent/http-parser, kqueue, epoll

优化的地方基本都是减少 parse 时的 malloc, 还有渲染时的拷贝

除了优化外还有一点是这个东西是伪同步的...

#2 楼 @ywjno 因为方法处理 option 求方便就先用新语法了, 还有模板渲染的局部变量代入也是用命名参数而不是 eval 弄的...

跟 node.js 比呢?expressjs

试试对比 Elixir 的 web framework https://github.com/elixir-lang/dynamo

# Run this app from Dynamo root with:
#
#     mix run -r examples/hello_world.exs --no-halt
#
defmodule HelloWorld do
  use Dynamo
  use Dynamo.Router

  config :dynamo, compile_on_demand: false
  config :server, port: 3030

  get "/" do
    conn.resp_body("Hello World!")
  end
end

HelloWorld.start_link
HelloWorld.run

#5 楼 @xieren58 在我的机器上这个 hello world 和 nodejs 差不多或许还会慢一点, 算上签名 session, 模板, 调用 web api 等各种拖慢响应速度特性的实验还没来得及做. 其实本来是功能才是重要的说...

- -。赞一个~

#9 楼 @lgn21st 最后的'呵呵'简直画龙点睛。

先 star, 关注这个项目的发展

#6 楼 @Los 折腾了一番 dynamo 终于跑起 hello world 了, 不过在我的机器上没有 nyara 多 worker 模式快

require 'nyara'

configure do
  set :env, 'production'
  set :workers, 4
end

get '/' do
  send_string 'hello world'
end

在我的机器上有 11k 到 13k TPS

#12 楼 @luikore dynamo 你那边测试得到的 TPS 是多少呢?

对楼主有一个小小的请求: 一定要记得把坑填上啊 ;)

支持一个

#12 楼 @luikore SMP 和 kernel-poll 模式都选对了么?

建个 nyara-benchmark 仓库吧

#3 楼 @luikore Mochi web 我弄过 10K 左右的速度。go 默认也那个速度好像。 但是 erlang 写 web 项目要人命的。那个东西不是用来写前段服务的,天生就是做大型构架的。

Again :) *哥威~~~~~~~

#13 楼 @Los #17 楼 @hlxwell #16 楼 @bhuztez

其实 ab 出 5k 还是 20k, 在最终产品上看不到区别的...

#19 楼 @luikore 那你发明什么轮子?

#20 楼 @bhuztez 但是 2k 和 5k 有区别啊

nyara 要做的东西是 exploit Fiber... 例如下面的例子, view 布局是结构化的, 但渲染是顺序可中断的

controller:

view = stream 'posts/index', layout: 'layout'
view.resume # 发送 head, 执行到 index.slim 的第一个 Fiber.yield

@ext_result = visit google # 调外网服务之类的很慢的, 等待时 queue 会激活其他 Fiber

view.resume # 执行到 index.slim 的第二个 Fiber.yield 并把这个东西前面的内容发到客户端

5.times do
  sleep 1 # sleep 是个 helper, 沉睡当前 Fiber 而不是进程/线程, 所以就不用定时器了
  view.resume # 执行到 index.slim 的下一个 Fiber.yield
end

view.end

平白无奇的 layout.slim

html
  head
    script ...
    link ...
  body
    == yield
    footer ...

用 Fiber.yield 加了插入点的 index.slim

...
- Fiber.yield
= @ext_result # 注意渲染 head 的时候这个东西还不存在
- Fiber.yield

- 10.times do
  = "sanchi!"
  = "pinchi!"
  Fiber.yield

就是类似 em-synchrony 完全不用 callback, 但是比 em-synchrony 快, 而且不需要 timer 相关的 API 了

如果在 libuv 之类的东西上做, 像写 outbound data 之类的还是会多产生很多复制, 而且实现的复杂度降不下来. 结合 fiber 做程序要简单很多. 简单就是健壮和速度...

求 erlang 版做法

#21 楼 @luikore Erlang 你按顺序写就可以了,因为解释器是 preemptive 的

感觉你这个和 Twisted 自带的没啥区别

http://twistedmatrix.com/documents/current/web/howto/twisted-templates.html

#22 楼 @bhuztez twisted template 看起来好难用的样子, 基于 xml 标签的模板基本都是又慢又吃内存的树解释器, 而且没看到渲染一部分就发送一部分的方法, 再者如果是在 wsgi 上就是跟 rack 差不多慢了...

wiki 里增加了手册, 修了一些在 linux 和不同环境的小 bug

#21 楼 @luikore fiber 怎么的都跑在单核上,erlang 可以

在 A 核上 render 页面, 在 B 核上取 google 的东西 还能跨服务器分布式处理打任务,最关键的是 erlang 这些特性都是自带的,他的天性就是做这些多核分布式的工作。

不过多核工作方式跟 fiber 不一样,如果多核协作好,应该比 fiber 快点。

#27 楼 @hlxwell 如果一个用户就用掉这么多核和机器, 其他用户还干什么... 还搞毛并发...

#28 楼 @luikore erlang 就是那种对我们一台机器用户来说没什么搞头的语言。 富二代语言啊 必须多台机器跑同一个应用才能体现出来优势。 erlang 是搞分布式的,你一台机器就跑多个用户,erlang 肯定没机会表现了。

我在看 elixir 觉得还是蛮有意思的。

#28 楼 @luikore

你可以限制 BEAM 只用一个核心的

To make a fault-tolerant system you need at least two computers

-- http://www.esug.org/data/ESUG2006/pres/erlang-smalltalkconference.pdf

gem install nyara --no-ri --no-rdoc ERROR: Could not find a valid gem 'nyara' (>= 0) in any repository ERROR: Possible alternatives: nyaa, yara

怎么装?

#31 楼 @yakczh 还没完全整好, 所以只有 pre 版本

gem ins --pre nyara --no-ri --no-rdoc
$ ab -n 10000 -c 100 http://127.0.0.1:3000/

Concurrency Level:      100
Time taken for tests:   2.120 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      2280000 bytes
HTML transferred:       210000 bytes
Requests per second:    4717.32 [#/sec] (mean)
Time per request:       21.198 [ms] (mean)
Time per request:       0.212 [ms] (mean, across all concurrent requests)
Transfer rate:          1050.34 [Kbytes/sec] receive

#33 楼 @huacnlee 是的, 加了签名 session 后慢了 n 多...

#34 楼 @luikore 所以默认要关掉 session,这样做 bm 的时候优势就大了..

PS. 看到 twitter 上 camping 的维护者对 Rails4 的加密 session 的吐槽:

we had encrypted session cookies in Camping 5 years ago, but removed it because it's just a silly idea https://twitter.com/judofyr/status/316915841868369922

#35 楼 @hooopo 信息太少了没看清楚怎么个傻法... 我下了 2007 年的 camping 看了下, 是没加密的啊 (另外连签名都没有)... 现在 camping 用的 rack.session 就和 rails 没区别...

加密 session 主要是对非 ssl 连接有点作用, 仍然能偷但是对用户来说能隐藏掉某些状态 (例如 admin 和非 admin 不能简单的通过 session 的正则判别了), 对闭源应用也稍微增加猜测程序结构的难度...

#36 楼 @luikore 好像说的是这个:

不过好像没提到加密 session,都是在说签名

做隐藏用户 ID 这种事情用加密 session 最合适了..

为什么 request 对象会有一些 response 相关的方法

[39] pry(#<Nyara::SimpleController>)> request
=> #<Nyara::Request:0x007fcaaab59f38>
[40] pry(#<Nyara::SimpleController>)> request.response_header
=> {}
[41] pry(#<Nyara::SimpleController>)> request.response_content_type
=> nil

可以在 librelist上开个 list,问问题和订阅方便一些..

#38 楼 @hooopo 开了, 但是怎么退订? 只能 mark as spam?

哦订阅: nyara@librelist.com

退订: nyara-unsubscribe@librelist.com

#38 楼 @hooopo response 本身就是很难和 request 切分的, 而且属性也不多...

有更新嗎??

#41 楼 @ksec 接近 0.1 了... 还剩下几个小问题, 搞定后会更新

@luikore 看到别人从 erlang 转成 python 就知道团队内用 erlang 做稍微复杂的事情就悲剧了。 http://code.mixpanel.com/2011/08/05/how-and-why-we-switched-from-erlang-to-python/ 不知道有没有试过 python 的东西进行比较。 http://www.gevent.org/ 似乎挺多团队用的说。

#19 楼 @luikore 在 mixpanel 就看得出区别了

Update: This repo is obsolete. The main point of event based IO is less memory for concurrent connections, and pay less time in CPU context switching, thus leading to higher performance benchmarks. But in real the heavy computation remains in ORMs like active record, the saved CPU time is insignificant while the implementation requires complex tweaks.

@luikore 可以再詳細解釋下嗎?

#45 楼 @ksec 因为要弄完还要花好多功夫, 一种做法是给数据库驱动做 monkey patch, 不过最终极的方法是用 LD_PRELOAD 去 hijack 系统 IO 函数, 但是得来的提升只是 hello world benchmark 上的, 加上 ActiveRecord 之类的就和多线程部署区别不大了. 另外部分 C-extension parsing 也可以提出来用在 rack 上.

需要 登录 后方可回复, 如果你还没有账号请 注册新账号