Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
Woo:
Writing a fast web server
8th European Lisp Symposium @ London, UK
April 21, 2015
Eitaro Fukamachi
Somewrite Co., Ltd.
I’m Eitaro Fukamachi
@nitro_idiot fukamachi
My Products
• Clack
• Caveman2
• CL-DBI
• quickdocs.org
• datafly
• SxQL
...and 25 other libraries
We’re hiring!
Woo
• HTTP server written in Common Lisp
• HTTP/0.9, HTTP/1.x
• Clack compliant
Woo
Clack?
• Abstraction layer of HTTP servers
Web server
Application
Web server Web server
Application Application
Clack?
• Abstraction layer of HTTP servers
Web server
Application
Web server Web server
Application Application
Clack
ex) Caveman2
• built on top of Clack
Web serverWeb server Web server
Caveman2

(Web framework)
Clack
ex) RESTAS (without Clack)
• directly built on top of Hunchentoot
Web server
Depends on Hunchentoot.
Can’t switch the back...
Clack-compliant
(woo:run
(lambda (env)
‘(200 (:content-type “text/plain”) (“Hello, World”))))
(clack:clackup
(lambda (env)...
Fast
https://github.com/fukamachi/woo#benchmarks
Fast — in the real worldreq/sec
0
33
65
98
130
Node.js Woo
127.18
76.73
1.6 times faster!
Let me tell
why I had to write
a fast HTTP server.
Wookie is slower than Node.js
• Wookie is 2 times slower than Node.js
Wookie is slower than Node.js
• Wookie is 2 times slower than Node.js
IS COMMON LISP SLOW???
Wookie is slower than Node.js
• Wookie is 2 times slower than Node.js
IS COMMON LISP SLOW???
NO WAY!
So, I decided to
write a faster one.
How could it be fast?
3 difficulties
in writing an HTTP servers
3 difficulties in HTTP server
• Network I/O is the largest bottleneck
• Need to handle a vast amount of requests
at once
• N...
3 tactics (no silver bullet)
1. Better architecture
2. Fast HTTP parsing
3. The libev event library
Tactic 1:
Better architecture
2 architectures:
Prefork vs Event-driven
Prefork
Worker
process
Worker
process
Worker
process
master process
Requests
accept connections
Responses
• Simple
• Fast ...
Prefork
Worker
process
Worker
process
Worker
process
master process
Requests
accept connections
Responses • Slow client ca...
Event-driven
• Handle many
clients at the same
time
• Asnyc ACCEPT/
READ/WRITE
• ex) Woo, Wookie,
Tornado, nginxServer pro...
Event-driven
• Single-threaded
Problem
Server process
(single-threaded)
Event loop
Woo took another way:
Multithreaded event-driven
Multithreaded event-driven
Server process
Event loop
listen on the same file descriptor
Server process
Event loop
Server pr...
Tactic 2:
Fast HTTP parsing
HTTP parsing can be a bottleneck
• Wookie's largest bottleneck is HTTP parsing
• http-parse (uses regular expression)
• fa...
A brief introduction of HTTP
HTTP request look like…
GET /media HTTP/1.1↵
Host: somewrite.jp↵
Connection: keep-alive↵
Accept: */*↵
↵
HTTP request look like…
GET /media HTTP/1.1↵
Host: somewrite.jp↵
Connection: keep-alive↵
Accept: */*↵
↵
First Line
Headers...
HTTP request look like…
GET /media HTTP/1.1↵
Host: somewrite.jp↵
Connection: keep-alive↵
Accept: */*↵
↵ CR + LF
CRLF * 2 a...
HTTP is…
• Text-based protocol. (not binary)
• Lines terminated with CRLF
• Very lenient.
• Ignore multiple spaces
• Allow...
And,
there’s another difficulty.
HTTP messages are
sent over a network.
Which means,
we need to think about
long & incomplete
HTTP messages.
There’s 2 ways
to resolve this problem.
1. Stateful (http-parser)
http-parser (used in Node.js)
• https://github.com/joyent/http-parser
• Written in C
• Ported from Nginx’s HTTP parser
• W...
http-parser (used in Node.js)
for (p=data; p != data + len; p++) {
…
switch (parser->state) {
case s_dead:
…
case s_start_...
http-parser (used in Node.js)
for (p=data; p != data + len; p++) {
…
switch (parser->state) {
case s_dead:
…
case s_start_...
http-parser (used in Node.js)
for (p=data; p != data + len; p++) {
…
switch (parser->state) {
case s_dead:
…
case s_start_...
2. Stateless (PicoHTTPParser)
PicoHTTPParser (used in H2O)
• https://github.com/h2o/picohttpparser
• Written in C
• Stateless
PicoHTTPParser (used in H2O)
• https://github.com/h2o/picohttpparser
• Written in C
• Stateless
• Reparse when the data is...
And fast-http is…
fast-http is in the middle
• Stateful
• Track state for every line, not every char
• 1.25 times faster than C http-parser.
Tactic 3:
The libev event library
libev
• Wrapper of epoll, kqueue, POSIX select, poll
• Thin
• Fast
libev
• Wrapper of epoll, kqueue, POSIX select, poll
• Thin
• Fast
• Poor Windows support
• Windows isn’t popular for runn...
Goal
Goal: What is fast enough?
• The initial goal was “Beating Node.js”
• Done
• Being the fastest HTTP server in Common
Lisp
...
Got a great Pull Request
See Also
• Clack: clacklisp.org
• fast-http: github.com/fukamachi/fast-http
• libev
• Woo: github.com/fukamachi/woo
You may be interested in
• Dexador: github.com/fukamachi/dexador
• HTTP client library built on top of fast-http
and usock...
Thanks.
EITARO FUKAMACHI
8arrow.org
@nitro_idiot fukamachi
Woo: Writing a fast web server @ ELS2015
Woo: Writing a fast web server @ ELS2015
Nächste SlideShare
Wird geladen in …5
×

Woo: Writing a fast web server @ ELS2015

4.586 Aufrufe

Veröffentlicht am

Demonstration at European Lisp Symposium 2015 in London, UK.

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Woo: Writing a fast web server @ ELS2015

  1. 1. Woo: Writing a fast web server 8th European Lisp Symposium @ London, UK April 21, 2015 Eitaro Fukamachi Somewrite Co., Ltd.
  2. 2. I’m Eitaro Fukamachi @nitro_idiot fukamachi
  3. 3. My Products • Clack • Caveman2 • CL-DBI • quickdocs.org • datafly • SxQL ...and 25 other libraries
  4. 4. We’re hiring!
  5. 5. Woo
  6. 6. • HTTP server written in Common Lisp • HTTP/0.9, HTTP/1.x • Clack compliant Woo
  7. 7. Clack? • Abstraction layer of HTTP servers Web server Application Web server Web server Application Application
  8. 8. Clack? • Abstraction layer of HTTP servers Web server Application Web server Web server Application Application Clack
  9. 9. ex) Caveman2 • built on top of Clack Web serverWeb server Web server Caveman2
 (Web framework) Clack
  10. 10. ex) RESTAS (without Clack) • directly built on top of Hunchentoot Web server Depends on Hunchentoot. Can’t switch the backend!! Supports only Hunchentoot Web server Web server RESTAS
 (Web framework)
  11. 11. Clack-compliant (woo:run (lambda (env) ‘(200 (:content-type “text/plain”) (“Hello, World”)))) (clack:clackup (lambda (env) ‘(200 (:content-type “text/plain”) (“Hello, World”))) :server :woo) Run with Clack
  12. 12. Fast https://github.com/fukamachi/woo#benchmarks
  13. 13. Fast — in the real worldreq/sec 0 33 65 98 130 Node.js Woo 127.18 76.73 1.6 times faster!
  14. 14. Let me tell why I had to write a fast HTTP server.
  15. 15. Wookie is slower than Node.js • Wookie is 2 times slower than Node.js
  16. 16. Wookie is slower than Node.js • Wookie is 2 times slower than Node.js IS COMMON LISP SLOW???
  17. 17. Wookie is slower than Node.js • Wookie is 2 times slower than Node.js IS COMMON LISP SLOW??? NO WAY!
  18. 18. So, I decided to write a faster one.
  19. 19. How could it be fast?
  20. 20. 3 difficulties in writing an HTTP servers
  21. 21. 3 difficulties in HTTP server • Network I/O is the largest bottleneck • Need to handle a vast amount of requests at once • Need to handle various HTTP clients
 (fast / slow / unstable)
  22. 22. 3 tactics (no silver bullet) 1. Better architecture 2. Fast HTTP parsing 3. The libev event library
  23. 23. Tactic 1: Better architecture
  24. 24. 2 architectures: Prefork vs Event-driven
  25. 25. Prefork Worker process Worker process Worker process master process Requests accept connections Responses • Simple • Fast for little simultaneous connections • ex) Hunchentoot, Unicorn, Apache
  26. 26. Prefork Worker process Worker process Worker process master process Requests accept connections Responses • Slow client can cause performance issue. • like Mobile users • Slowloris attack blocking! ・・・ Problem
  27. 27. Event-driven • Handle many clients at the same time • Asnyc ACCEPT/ READ/WRITE • ex) Woo, Wookie, Tornado, nginxServer process (single-threaded) Event loop
  28. 28. Event-driven • Single-threaded Problem Server process (single-threaded) Event loop
  29. 29. Woo took another way: Multithreaded event-driven
  30. 30. Multithreaded event-driven Server process Event loop listen on the same file descriptor Server process Event loop Server process Event loop
  31. 31. Tactic 2: Fast HTTP parsing
  32. 32. HTTP parsing can be a bottleneck • Wookie's largest bottleneck is HTTP parsing • http-parse (uses regular expression) • fast-http (byte by byte parser) • 6000 times faster than http-parse
  33. 33. A brief introduction of HTTP
  34. 34. HTTP request look like… GET /media HTTP/1.1↵ Host: somewrite.jp↵ Connection: keep-alive↵ Accept: */*↵ ↵
  35. 35. HTTP request look like… GET /media HTTP/1.1↵ Host: somewrite.jp↵ Connection: keep-alive↵ Accept: */*↵ ↵ First Line Headers Body (empty, in this case)
  36. 36. HTTP request look like… GET /media HTTP/1.1↵ Host: somewrite.jp↵ Connection: keep-alive↵ Accept: */*↵ ↵ CR + LF CRLF * 2 at the end of headers
  37. 37. HTTP is… • Text-based protocol. (not binary) • Lines terminated with CRLF • Very lenient. • Ignore multiple spaces • Allow continuous header values
  38. 38. And, there’s another difficulty.
  39. 39. HTTP messages are sent over a network.
  40. 40. Which means, we need to think about long & incomplete HTTP messages.
  41. 41. There’s 2 ways to resolve this problem.
  42. 42. 1. Stateful (http-parser)
  43. 43. http-parser (used in Node.js) • https://github.com/joyent/http-parser • Written in C • Ported from Nginx’s HTTP parser • Written as Node.js’s HTTP parser • Stateful
  44. 44. http-parser (used in Node.js) for (p=data; p != data + len; p++) { … switch (parser->state) { case s_dead: … case s_start_req_or_res: … case s_res_or_resp_H: … } }
  45. 45. http-parser (used in Node.js) for (p=data; p != data + len; p++) { … switch (parser->state) { case s_dead: … case s_start_req_or_res: … case s_res_or_resp_H: … } } Process char by char Do something for each state
  46. 46. http-parser (used in Node.js) for (p=data; p != data + len; p++) { … switch (parser->state) { case s_dead: … case s_start_req_or_res: … case s_res_or_resp_H: … } } Process char by char Do something for each state Executed for every char!!
  47. 47. 2. Stateless (PicoHTTPParser)
  48. 48. PicoHTTPParser (used in H2O) • https://github.com/h2o/picohttpparser • Written in C • Stateless
  49. 49. PicoHTTPParser (used in H2O) • https://github.com/h2o/picohttpparser • Written in C • Stateless • Reparse when the data is incomplete • Most HTTP request is small
  50. 50. And fast-http is…
  51. 51. fast-http is in the middle • Stateful • Track state for every line, not every char • 1.25 times faster than C http-parser.
  52. 52. Tactic 3: The libev event library
  53. 53. libev • Wrapper of epoll, kqueue, POSIX select, poll • Thin • Fast
  54. 54. libev • Wrapper of epoll, kqueue, POSIX select, poll • Thin • Fast • Poor Windows support • Windows isn’t popular for running an HTTP server
  55. 55. Goal
  56. 56. Goal: What is fast enough? • The initial goal was “Beating Node.js” • Done • Being the fastest HTTP server in Common Lisp • Done
  57. 57. Got a great Pull Request
  58. 58. See Also • Clack: clacklisp.org • fast-http: github.com/fukamachi/fast-http • libev • Woo: github.com/fukamachi/woo
  59. 59. You may be interested in • Dexador: github.com/fukamachi/dexador • HTTP client library built on top of fast-http and usocket.
  60. 60. Thanks.
  61. 61. EITARO FUKAMACHI 8arrow.org @nitro_idiot fukamachi

×