• Like

Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Fscons scalable appplication transfers

  • 2,198 views
Uploaded on

Daniel Stenberg's talk at FSCONS 2010 about client-side scalable application layer transfers

Daniel Stenberg's talk at FSCONS 2010 about client-side scalable application layer transfers

More in: Technology , Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
2,198
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
4
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Scalable application layer transfers
  • 2. Daniel Stenberg
    • Free Software
    • 3. Network hacker, code and IETF
    • 4. Embedded developer
    • 5. Consultant
    Email: [email_address] Twitter: @bagder Web: daniel.haxx.se Blog: daniel.haxx.se/blog
  • 6. Agenda
    • Traditional network client
    • 7. … applied to libcurl
    • 8. C10K
    • 9. … applied to libcurl
  • 10. Protocol stack Contents Application Transport Internet Link
  • 11. libcurl
    • curl.haxx.se
    • 12. Very portable C library
    • 13. Application protocol transfers: DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP
    • 14. Roots from 1997
    • 15. MIT licensed
    • 16. Daniel is lead developer
  • 17. A typical client
    • Create socket
    • 18. Connect socket
    • 19. Select() for data to read or write
    • 20. Read or write data
    • 21. Loop
  • 22. pseudo C code
      WARNING the following source code examples are not complete and they resemble C code
  • 23. int main(int argc, char *argv[]) { int sock; /* Socket descriptor */ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError(&quot;socket() failed&quot;); /* it would resolve the host name here */ if (connect(sock to server)) DieWithError(&quot;connect() failed&quot;); do { select(maxfd+1, sock, …); /* wait for socket to become readable or writable */ if(check sock if writable) send(sock, string, string_len, 0); if(check sock if readable) recv(sock, string, string_len, 0); } while(everything is fine); close(sock); exit(0); } School book example 1 2 1 3 4 5
  • 24. Simple case works fine
    • Easy to read
    • 25. Fast to write
    • 26. Easy to learn and teach
  • 27. int main(int argc, char *argv[]) { int sock[NUM_CONNS]; /* Socket descriptors */ for(i=0; i< NUM_CONNS; i++) { if ((sock[i] = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError(&quot;socket() failed&quot;); if (connect(sock[i] to server[i])) DieWithError(&quot;connect() failed&quot;); do { /* set up the bitmasks for select() */ select(maxfd+1, sock, …); /* wait for any socket to become readable or writable */ for(i=0; i< NUM_CONNS; i++) { if(check sock[i] if writable) send(sock, string, string_len, 0); if(check sock[i] if readable) recv(sock, string, string_len); } } while(everything is fine); close(sock); exit(0); } More connections 1 2 1 3 4 5
  • 28. int main(int argc, char *argv[]) { int sock[NUM_CONNS]; /* Socket descriptors */ for(i=0; i< NUM_CONNS; i++) { if ((sock[i] = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) DieWithError(&quot;socket() failed&quot;); if (connect(sock[i] to server[i])) DieWithError(&quot;connect() failed&quot;); do { /* set up the bitmasks for select() */ select(maxfd+1, sock, …); /* wait for any socket to become readable or writable */ for(i=0; i< NUM_CONNS; i++) { if(check sock[i] if writable) send(sock, string, string_len, 0); if(check sock[i] if readable) recv(sock, string, string_len); } } while(everything is fine); close(sock); exit(0); } More connections
  • 29. Many connections
    • Quickly degrades
    • 30. select() and poll() suck
    • 31. select() slightly more due to FD_SETSIZE
    • 32. Threads help to some degree, but...
  • 33. what about libcurl
    • examples in C
    • 34. has bindings for 40 languages
  • 35. libcurl simple app int main(void) { CURL *curl; CURLcode res; curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, &quot;http://example.com&quot;); res = curl_easy_perform(curl); /* always cleanup */ curl_easy_cleanup(curl); } return 0; }
  • 36. easy interface
    • easy to write
    • 37. synchronous
    • 38. supports many protocols in one go
    • 39. made for single transfers
  • 40. libcurl multi app int main(int argc, char **argv) { handle1 = curl_easy_init(); handle2 = curl_easy_init(); curl_easy_setopt(handle1, CURLOPT_URL, &quot;http://www.example.com/&quot;); curl_easy_setopt(handle2, CURLOPT_URL, &quot;http://fscons.org/&quot;); multi_handle = curl_multi_init(); curl_multi_add_handle(multi_handle, handle1); curl_multi_add_handle(multi_handle, handle2); curl_multi_perform(multi_handle, &still_running); while(still_running) { curl_multi_timeout(multi_handle, &curl_timeo); curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); if(rc says timeout or readable/writable sockets) curl_multi_perform(multi_handle, &still_running); } curl_multi_cleanup(multi_handle); curl_easy_cleanup(http_handle); curl_easy_cleanup(http_handle2); return 0; } 1 2 5 4 6 3 7 8
  • 41. libcurl multi app int main(int argc, char **argv) { handle1 = curl_easy_init(); handle2 = curl_easy_init(); curl_easy_setopt(handle1, CURLOPT_URL, &quot;http://www.example.com/&quot;); curl_easy_setopt(handle2, CURLOPT_URL, &quot;http://fscons.org/&quot;); multi_handle = curl_multi_init(); curl_multi_add_handle(multi_handle, handle1); curl_multi_add_handle(multi_handle, handle2); curl_multi_perform(multi_handle, &still_running); while(still_running) { curl_multi_timeout(multi_handle, &curl_timeo); curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); if(rc says timeout or readable/writable sockets) curl_multi_perform(multi_handle, &still_running); } curl_multi_cleanup(multi_handle); curl_easy_cleanup(http_handle); curl_easy_cleanup(http_handle2); return 0; }
  • 42. multi interface
    • several “easy” handles dealt with combined
    • 43. made for simultaneous transfers
    • 44. still easy to write and read
    • 45. but: relies on select()
  • 46. select with many
  • 47. Scale to c10K
    • 10000 simultaneous connections
    • 48. not as easy as it may sound
  • 49. A better way
    • event-based
    • 50. react only on the sockets that have changed actions
    • 51. no “check for action”
    • 52. no loops
  • 53. really scalable
  • 54. not that portable
    • There's no POSIX for event-based
    • 55. The portable libs don't support all platforms
    • 56. epoll (Linux), kqueue (FreeBSD, NetBSD, OpenBSD, Darwin), /dev/poll (Solaris, HPUX), pollset (AIX), Event Completion (Solaris 10), I/O Completion Ports (Microsoft Windows)
  • 57. libev and libevent
    • potent event libraries we base the examples on in this presentation
    • 58. they support a subset of platforms
    • 59. the examples are not complete now either
  • 60. event-based basics
    • detail what sockets we work with and what do we wait for on the sockets
    • 61. timeouts
    • 62. wait until something happens
  • 63. simple event client int function(int socketfd) { ev = ev_default_loop(); ev_timer_init(..., timer_callback, …); ev_io_init(ev, event_callback, socketfd, WHAT); ev_loop(ev); /* sit here until done */ } int timer_callback(...) { /* timer expired! */ } int event_callback(..., int socketfd, ...) { /* something happened on my socket, now we recv or send etc */ }
  • 64. event based compared
    • different code-flow
    • 65. might require a different state machine for the protocol
    • 66. again: not widely portable
  • 67. Other ways to avoid wrongs
    • one thread per connection with blocking sockets
    • 68. threads with non-blocking i/o to handle N connections each
  • 69. using libcurl scalable
    • “multi_socket” API added 2006
    • 70. tells the app what sockets to wait for what on
    • 71. app then speaks with event library
    • 72. avoids select()
    • 73. event system agnostic
  • 74. libcurl multi_socket bindings
    • not always supported
    • 75. a matter of writing the glue code correct – you can help!
  • 76. multi_socket example int main() { CURLM *multi = curl_multi_init(); CURL *easy; curl_multi_setopt(..., CURLMOPT_SOCKETFUNCTION, socket_cb); curl_multi_setopt(..., CURLMOPT_TIMERFUNCTION, timer_cb); easy = curl_easy_init(); curl_easy_setopt(..., CURLOPT_URL, …); curl_multi_add_handle(..., easy); event_dispatch(); /* start the libevent dispatch loop */ } int event_cb(...) { /* event library found event on libcurl's socket, act */ curl_multi_socket_action(..., action, ...); } int socket_cb(...) { /* called when libcurl adds, removes or changes a socket that we must deal with */ event_set(..., event_cb); /* tell event lib about setup */ }
  • 77. Scales?
    • done 70,000+ connections
    • 78. port numbers are 16 bit
    • 79. callbacks take time thus limit throughput
  • 80. Which protocols?
    • (almost) all network based ones libcurl support! (DICT, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS and TFTP)
  • 81. Caveats?
    • yeah sure, but...
    • 82. c-ares for name resolving
    • 83. not everything is non-blocking
  • 84. More factors
    • Network stack inefficiency
    • 85. Stack size?
    • 86. Memory / mallocs
    • 87. “Other” code may slow down things
    • 88. Copy copy copy copy ...
  • 89. For you who fell asleep
    • old style socket applications don't scale
    • 90. use event based concepts
    • 91. libcurl can too
  • 92. libcurl is...
    • entirely open source
    • 93. in need of your help!
    • 94. at http://curl.haxx.se/libcurl/