Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Next Gen Networking Infrastructure with Rust

116 vues

Publié le

Video and slides synchronized, mp3 and slide download available at URL https://bit.ly/2ES9ISH.

Carl Lerche shows how Rust’s “zero cost abstractions” can be leveraged to provide a networking platform that provides expressiveness, speed, and safety with tradeoffs between them. He describes how these techniques are used in Conduit, a “service mesh” proxy for the next generation of cloud native applications. Filmed at qconnewyork.com.

Carl Lerche is a software engineer at Buoyant. He has authored and contributes to many open source Rust libraries, including Tokio, a platform for writing fast networking code.

Publié dans : Technologie
  • Soyez le premier à commenter

Next Gen Networking Infrastructure with Rust

  1. 1. Next Gen Networking Infrastructure With Rust
  2. 2. InfoQ.com: News & Community Site • 750,000 unique visitors/month • Published in 4 languages (English, Chinese, Japanese and Brazilian Portuguese) • Post content from our QCon conferences • News 15-20 / week • Articles 3-4 / week • Presentations (videos) 12-15 / week • Interviews 2-3 / week • Books 1 / month Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/ rust-infrastructure
  3. 3. Presented at QCon New York www.qconnewyork.com Purpose of QCon - to empower software development by facilitating the spread of knowledge and innovation Strategy - practitioner-driven conference designed for YOU: influencers of change and innovation in your teams - speakers and topics driving the evolution and innovation - connecting and catalyzing the influencers and innovators Highlights - attended by more than 12,000 delegates since 2007 - held in 9 cities worldwide
  4. 4. Hi, I’m @carllerche
  5. 5. Let’s write a database!
  6. 6. Most newer databases are written in a language that includes a runtime.
  7. 7. C / C++
  8. 8. Memory management we’ll do it live…
  9. 9. SEGV
  10. 10. Heartbleed, cloudbleed, WannaCry
  11. 11. – Software developer who accidentally shipped remote code execution vulnerabilities to millions of computers “Just use linting tools”
  12. 12. Speed Safety
  13. 13. Speed Safety
  14. 14. Checks at compile time
  15. 15. Ownership
  16. 16. Data has one owner
  17. 17. Compiles fn print(s: String) { println!("{}", s); } let foo = String::new(); let bar = foo; print(bar);
  18. 18. Compiles fn print(s: String) { println!("{}", s); } let foo = String::new(); let bar = foo; print(bar);
  19. 19. fn print(s: String) { println!("{}", s); } let foo = String::new(); let bar = foo; print(foo); | 8 | let bar = foo; | --- value moved here 9 | 10 | print(foo); | ^^^ value used here after move | = note: move occurs because `foo` has type `std::string::String`, which does not implement the `Copy` trait
  20. 20. Data is borrowed
  21. 21. Compiles fn print(s: &String) { println!("{}", s); } let foo = String::new(); let bar = &foo; print(&foo); print(bar);
  22. 22. fn print(s: &String) { println!("{}", s); } fn drop(s: String) {} let foo = String::new(); let bar = &foo; print(&foo); drop(foo); print(bar); | 10 | let bar = &foo; | --- borrow of `foo` occurs here ... 14 | drop(foo); | ^^^ move out of `foo` occurs here
  23. 23. Mutable borrows
  24. 24. fn print(s: &mut String) { println!("{}", s); } let mut foo = String::new(); let bar = &mut foo; print(&mut foo); | 8 | let bar = &mut foo; | --- first mutable borrow | occurs here 9 | 10 | print(&mut foo); | ^^^ second mutable borrow | occurs here 11 | } | - first borrow ends here
  25. 25. let mut vec = vec![]; vec.push(String::new()); // lots of code here let val = &vec[0]; // lots of code here vec.push(String::new()); // lots of code here println!("{}", val); | 9 | let val = &vec[0]; | --- immutable borrow occurs | here ... 13 | vec.push(String::new()); | ^^^ mutable borrow occurs here ... 19 | } | - immutable borrow ends here
  26. 26. let handle1 = Rc::new(my_data); let handle2 = handle1.clone(); drop(handle1); println!("data = {}", handle2);
  27. 27. struct Rc<T> { inner: *mut Inner<T>, } struct Inner<T> { value: T, ref_count: usize, } impl<T> Rc<T> { fn clone(&self) -> Rc<T> { unsafe { (*self.inner).ref_count += 1; } Rc { inner: self.inner } } } impl<T> Drop<T> { fn drop(&mut self) { unsafe { (*self.inner.ref_count) -= 1; if *self.inner.ref_count == 0 { // Free memory } } } }
  28. 28. I’m sorry, Dave. I’m afraid I can’t do that.
  29. 29. Fearless concurrency
  30. 30. Compiles let (tx, rx) = channel(); thread::spawn(|| { for msg in rx { … } }); tx.send(my_msg);
  31. 31. let (tx, rx) = channel(); thread::spawn(|| { for msg in rx { … } }); tx.send(my_msg); println!("{}", my_msg); error[E0382]: use of moved value: `my_msg` | 12 | tx.send(my_msg); | ------ value moved here 13 | println!("msg = {}", my_msg); | ^^^^^^ value used | here after move | = note: move occurs because `my_msg` has type `std::string::String`, which does not implement the `Copy` trait
  32. 32. Compiles let mutex = Arc::new(Mutex::new(data)); thread::spawn(|| { // use mutex }); // lock() -> Guard<‘a, T> let d = mutex.lock()?; println!("{}", d);
  33. 33. Modern Language Features • Closures • Type inference • Traits • Package manager • Pattern matching • Macros
  34. 34. Fast, Reliable, Productive: Pick Three
  35. 35. Can the principles of Rust be applied to a networking library?
  36. 36. Fastest, Safest
  37. 37. • Epoll, kqueue, IOCP backed I/O • Timers • Task scheduling (N:M, current thread,…) • Filesystem access • Child processes
  38. 38. • Cancellation • Backpressure
  39. 39. Secret: Do no work
  40. 40. let server = TcpListener::bind(&local_addr)?; let server = sever.incoming().for_each(move |src| { let connection = TcpStream::connect(&remote_addr) .and_then(|move |dst| copy(src, dst)); // Run asynchronously in the background tokio::spawn(connection) }); tokio::spawn(server);
  41. 41. Futures
  42. 42. TcpStream::connect(&remote_addr) .and_then(move |dst| { … }) .and_then(|foo| { … })
  43. 43. let fut_1 = copy(src_rd, dst_wr); let fut_2 = copy(dst_rd, src_wr); let fut_3 = fut_1.join(fut_2);
  44. 44. Zero cost
  45. 45. Epoll • Non-blocking sockets • Event queue
  46. 46. let socket = bind(remote_addr); epoll.register(socket, token: 0); let clients = State::new(); for event in epoll.poll(): match event.token: 0 => while socket.is_ready(): let client = socket.accept(); let token = clients.store(client); epoll.register(client, token: token); token => let client = clients[token]; process(client);
  47. 47. 1. Connect a socket 2. Send handshake message 3. Receive handshake message 4. Send request 5. Receive request enum SocketState { Connecting, SendingHandshake, ReceivingHandshake, SendingRequest, ReceivingResponse, }
  48. 48. Fast • No runtime allocations • No dynamic dispatch • No copying / growing the stack • No garbage collection
  49. 49. After compilation, Tokio is equivalent.
  50. 50. Pull, not push
  51. 51. struct DrainTcpStream { nread: u64, callback: Option<Box<Fn(u64)>>, } Closure Allocation
  52. 52. drain_socket .then(...) .then(...) .then(...)
  53. 53. drain_socket Callback Callback Callback
  54. 54. drain_socket Callback Callback Callback Val
  55. 55. drain_socket Callback Callback Callback Val
  56. 56. drain_socket Callback Callback Callback Val Callback
  57. 57. channel Callback Callback Callback Val
  58. 58. channel Callback Callback Callback Val Val Val
  59. 59. struct DrainTcpStream { socket: TcpStream, nread: u64, } fn poll(&mut self) -> Async<u64> { let mut buf = [0; 1024]; loop { match self.socket.read(&mut buf) { Async::Ready(0) => return Async::Ready(self.nread), Async::Ready(n) => self.nread += n, Async::NotReady => return Async::NotReady, } } }
  60. 60. drain_socket .then(...) .then(...) .then(...)
  61. 61. enum Then<A, B, F> { First(A, F), Second(B), } fn poll(&mut self) -> Async<B::Item> { loop { let fut_b = match *self { Then::First(ref mut fut_a, ref f) => { match fut_a.poll() { Async::Ready(v) => f(v), Async::NotReady => Async::NotReady, } } Then::Second(ref mut fut_b) => return fut_b.poll(), } *self = Then::Second(fut_b); } }
  62. 62. drain_socket Callback Callback Consumer Poll
  63. 63. drain_socket Callback Callback Consumer Not Ready
  64. 64. drain_socket Callback Callback Consumer Poll
  65. 65. drain_socket Callback Callback Consumer Val
  66. 66. drain_socket Callback Callback Consumer ValReady:
  67. 67. channel Callback Callback Consumer Val
  68. 68. channel Callback Callback Consumer Val Not Ready
  69. 69. channel Callback Callback Consumer Val Poll
  70. 70. channel Callback Callback Consumer ValReady:
  71. 71. 1. Connect a socket 2. Send handshake message 3. Receive handshake message 4. Send request 5. Receive request TcpStream::connect(&remote_addr) .then(|sock| io::write(sock, handshake)) .then(|sock| io::read_exact(sock, 10)) .then(|(sock, handshake)| { validate(handshake); io::write(sock, request) }) .then(|sock| io::read_exact(sock, 10)) .then(|(sock, response)| { process(response) })
  72. 72. 1. Connect a socket 2. Send handshake message 3. Receive handshake message 4. Send request 5. Receive request enum SocketState { Connecting, SendingHandshake, ReceivingHandshake, SendingRequest, ReceivingResponse, }
  73. 73. tokio::spawn(task)
  74. 74. Thread pool Epoll Timer Task Task Socket Drivers Executor
  75. 75. Thread pool Epoll Timer Task Task Socket Drivers Executor
  76. 76. Thread pool Epoll Timer Task Task Socket Drivers Executor
  77. 77. Thread pool Epoll Timer Task Task Socket Drivers Executor
  78. 78. Thread pool Epoll Timer Task Task Socket Drivers Executor
  79. 79. task::current() -> Task Task::notify()
  80. 80. Have your 🍰 and 🍽 it too.
  81. 81. Tokio + Rust gets you speed and safety.
  82. 82. Thanks https://tokio.rs https://conduit.io
  83. 83. Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/ rust-infrastructure

×