Network Applications: High-performance Server Design Y. Richard Yang 2/17/2016.

Slides:



Advertisements
Similar presentations
Concurrency Important and difficult (Ada slides copied from Ed Schonberg)
Advertisements

CMSC 330: Organization of Programming Languages Threads Classic Concurrency Problems.
Concurrency 101 Shared state. Part 1: General Concepts 2.
CS 5704 Fall 00 1 Monitors in Java Model and Examples.
1 Java threads: synchronization. 2 Thread states 1.New: created with the new operator (not yet started) 2.Runnable: either running or ready to run 3.Blocked:
Network Applications: High-Performance Network Servers Y. Richard Yang 10/01/2013.
Liang, Introduction to Java Programming, Seventh Edition, (c) 2009 Pearson Education, Inc. All rights reserved Chapter 5 Multithreading and.
Concurrent Client server L. Grewe. Reveiw: Client/server socket interaction: TCP wait for incoming connection request connectionSocket = welcomeSocket.accept()
Synchronization in Java Fawzi Emad Chau-Wen Tseng Department of Computer Science University of Maryland, College Park.
Fundamentals of Python: From First Programs Through Data Structures
Threads in Java1 Concurrency Synchronizing threads, thread pools, etc.
1 CSCI 6900: Design, Implementation, and Verification of Concurrent Software Eileen Kraemer August 19 th, 2010 The University of Georgia.
Concurrency Recitation – 2/24 Nisarg Raval Slides by Prof. Landon Cox.
1 Thread II Slides courtesy of Dr. Nilanjan Banerjee.
Threads some important concepts Simon Lynch
Java Threads 11 Threading and Concurrent Programming in Java Introduction and Definitions D.W. Denbo Introduction and Definitions D.W. Denbo.
1 (Worker Queues) cs What is a Thread Pool? A collection of threads that are created once (e.g. when a server starts) That is, no need to create.
Operating Systems ECE344 Ashvin Goel ECE University of Toronto Mutual Exclusion.
Internet Software Development Controlling Threads Paul J Krause.
Practice Session 8 Blocking queues Producers-Consumers pattern Semaphore Futures and Callables Advanced Thread Synchronization Methods CountDownLatch Thread.
Synchronized and Monitors. synchronized is a Java keyword to denote a block of code which must be executed atomically (uninterrupted). It can be applied.
CSC321 Concurrent Programming: §5 Monitors 1 Section 5 Monitors.
Synchronizing threads, thread pools, etc.
Threaded Programming in Python Adapted from Fundamentals of Python: From First Programs Through Data Structures CPE 401 / 601 Computer Network Systems.
Concurrency in Java Brad Vander Zanden. Processes and Threads Process: A self-contained execution environment Thread: Exists within a process and shares.
In Java processes are called threads. Additional threads are associated with objects. An application is associated with an initial thread via a static.
Advanced Concurrency Topics Nelson Padua-Perez Bill Pugh Department of Computer Science University of Maryland, College Park.
Java Thread and Memory Model
Threads Doing Several Things at Once. Threads n What are Threads? n Two Ways to Obtain a New Thread n The Lifecycle of a Thread n Four Kinds of Thread.
SPL/2010 Guarded Methods and Waiting 1. SPL/2010 Reminder! ● Concurrency problem: asynchronous modifications to object states lead to failure of thread.
Threads in Java1 Concurrency Synchronizing threads, thread pools, etc.
CS533 – Spring Jeanie M. Schwenk Experiences and Processes and Monitors with Mesa What is Mesa? “Mesa is a strongly typed, block structured programming.
CMSC 330: Organization of Programming Languages Threads.
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Computer Systems Principles Synchronization Emery Berger and Mark Corner University.
Threads in Java Threads Introduction: After completing this chapter, you will be able to code your own thread, control them efficiently without.
Threads b A thread is a flow of control in a program. b The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
Network Applications: Network App Programming: HTTP/1.1/2; High-performance Server Design Y. Richard Yang 2/15/2016.
Concurrent Programming in Java Based on Notes by J. Johns (based on Java in a Nutshell, Learning Java) Also Java Tutorial, Concurrent Programming in Java.
Java.util.concurrent package. concurrency utilities packages provide a powerful, extensible framework of high-performance threading utilities such as.
Tutorial 2: Homework 1 and Project 1
CSCD 330 Network Programming
Threads in Java Two ways to start a thread
Multithreading / Concurrency
Threaded Programming in Python
Thread Pools (Worker Queues) cs
Multi Threading.
CS703 – Advanced Operating Systems
Practice Session 8 Lockfree LinkedList Blocking queues
Network Applications: HTTP/1
Threads, Concurrency, and Parallelism
Threads Chate Patanothai.
Multithreading Chapter 23.
Synchronization Lecture 23 – Fall 2017.
Condition Variables and Producer/Consumer
Multithreading.
Condition Variables and Producer/Consumer
Producer-Consumer Problem
Multithreading.
Concurrency in Java Last Updated: Fall 2010 Paul Ammann SWE 619.
Lecture 9 Synchronization.
Computer Science 2 06A-Java Multithreading
CSE 153 Design of Operating Systems Winter 19
Network Applications: High-Performance Server Design (Thread, Async)
Threads and Multithreading
Software Engineering and Architecture
CSE 542: Operating Systems
CSE 542: Operating Systems
some important concepts
More concurrency issues
Synchronization and liveness
Presentation transcript:

Network Applications: High-performance Server Design Y. Richard Yang 2/17/2016

2 Outline r Admin and recap r High-performance network server design

3 Recap: Substantial Efforts to Speedup Basic HTTP/1.0 r Reduce the number of objects fetched [Browser cache] r Reduce data volume [Compression of data] r Reduce the latency to the server to fetch the content [Proxy cache] r Increase concurrency [Multiple TCP connections] r Remove the extra RTTs to fetch an object [Persistent HTTP, aka HTTP/1.1] r Asynchronous fetch (multiple streams) using a single TCP [HTTP/2] r Server push [HTTP/2] r Header compression [HTTP/2]

Recap: Server Processing Steps Accept Client Connection Read Request Find File Send Response Header Read File Send Data may block waiting on disk I/O may block waiting on network

Recap: Design Server Limited Only by the Bottleneck CPU DISK Before NET CPU DISK NET After

Recap: Per-Request Thread Server 6 main() { ServerSocket s = new ServerSocket(port); while (true) { Socket conSocket = s.accept(); RequestHandler rh = new RequestHandler(conSocket); Thread t = new Thread (rh); t.start(); } main thread thread starts thread ends thread ends

Recap: Problem of Per-Request Thread r High thread creation/deletion overhead r Too many threads  resource overuse  throughput meltdown  response time explosion

Discussion: How to Address the Issue

9 Outline r Admin and recap r High-performance network server design m Overview m Threaded servers Per-request thread Thread pool

Using a Fixed Set of Threads (Thread Pool) r Design issue: how to distribute the requests from the welcome socket to the thread workers 10 welcome socket Thread 1Thread 2 Thread K

Design 1: Threads Share Access to the welcomeSocket 11 WorkerThread { void run { while (true) { Socket myConnSock = welcomeSocket.accept(); // process myConnSock myConnSock.close(); } // end of while } welcome socket Thread 1Thread 2 Thread K sketch; not working code

Design 2: Producer/Consumer 12 welcome socket Main thread Thread 2 Thread K Thread 1 Q: Dispatch queue main { void run { while (true) { Socket con = welcomeSocket.accept(); Q.add(con); } // end of while } WorkerThread { void run { while (true) { Socket myConnSock = Q.remove(); // process myConnSock myConnSock.close(); } // end of while } sketch; not working code

Common Issues Facing Designs 1 and 2 r Both designs involve multiple threads modifying the same data concurrently m Design 1: m Design 2: r In our original TCPServerMT, do we have multiple threads modifying the same data concurrently? 13 welcomeSocket Q

Concurrency and Shared Data r Concurrency is easy if threads don’t interact m Each thread does its own thing, ignoring other threads m Typically, however, threads need to communicate/coordinate with each other m Communication/coordination among threads is often done by shared data 14

Simple Example public class ShareExample extends Thread { private static int cnt = 0; // shared state, count // total increases public void run() { int y = cnt; cnt = y + 1; } public static void main(String args[]) { Thread t1 = new ShareExample(); Thread t2 = new ShareExample(); t1.start(); t2.start(); Thread.sleep(1000); System.out.println(“cnt = “ + cnt); } 15 Q: What is the result of the program?

Simple Example What if we add a println: int y = cnt; System.out.println(“Calculating…”); cnt = y + 1; 16

What Happened? r A thread was preempted in the middle of an operation  The operations from reading to writing cnt should be atomic with no interference access to cnt from other threads r But the scheduler interleaves threads and caused a race condition r Such bugs can be extremely hard to reproduce, and also hard to debug 17

Synchronization r Refers to mechanisms allowing a programmer to control the execution order of some operations across different threads in a concurrent program. r We use Java as an example to see synchronization mechanisms r We'll look at locks first. 18

Java Lock (1.5) r Only one thread can hold a lock at once r Other threads that try to acquire it block (or become suspended) until the lock becomes available r Reentrant lock can be reacquired by same thread m As many times as desired m No other thread may acquire a lock until it has been released the same number of times that it has been acquired m Do not worry about the reentrant perspective, consider it a lock 19 interface Lock { void lock(); void unlock();... /* Some more stuff, also */ } class ReentrantLock implements Lock {... }

Java Lock r Fixing the ShareExample.java problem 20 import java.util.concurrent.locks.*; public class ShareExample extends Thread { private static int cnt = 0; static Lock lock = new ReentrantLock(); public void run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } … }

Java Lock r It is recommended to use the following pattern 21 … lock.lock(); try { // processing body } finally { lock.unlock(); }

Java synchronized r This pattern is really common m Acquire lock, do something, release lock after we are done, under any circumstances, even if exception was raised, the method returned in the middle, etc. r Java has a language construct for this m synchronized (obj) { body } r Every Java object has an implicitly associated lock m Obtains the lock associated with obj m Executes body m Release lock when scope is exited m Even in cases of exception or method return 22

Discussion r An object and its associated lock are different ! r Holding the lock on an object does not affect what you can do with that object in any way r Examples: m synchronized(o) {... } // acquires lock named o m o.f (); // someone else can call o’s methods m o.x = 3; // someone else can read and write o’s fields 23 object o o’s lock

Synchronization on this  A program can often use this as the object to lock r Does the program above have a data race? m No, both threads acquire locks on the same object before they access shared data 24 class C { int cnt; void inc() { synchronized (this) { cnt++; } // end of sync } // end of inc } C c = new C(); Thread 1 c.inc(); Thread 2 c.inc();

Synchronization on this r Does the program above have a data race? m No, both threads acquire locks on the same object before they access shared data 25 class C { static int cnt; void inc() { synchronized (this) { cnt++; } // end of sync } // end of inc void dec() { synchronized (this) { cnt--; } // end of sync } // end of dec } C c = new C(); Thread 1 c.inc(); Thread 2 c.dec();

Example r See m ShareWelcome/Server.java m ShareWelcome/ServiceThread.java 26

Discussion  You would not need the lock for accept if Java were to label the call as thread safe (synchronized)  One reason Java does not specify accept as thread safe is that one could register your own socket implementation with ServerSocket.setSocketFactory ServerSocket.setSocketFactory r Always consider thread safety in your design m If a resource is shared through concurrent read/write, write/write), consider thread-safe issues. 27

Why not Synchronization r Synchronized method invocations generally are going to be slower than non-synchronized method invocations r Synchronization gives rise to the possibility of deadlock, a severe performance problem in which your program appears to hang 28

Synchronization Overhead r Try SyncOverhead.java 29 MethodTime (ms; 5,000,000 exec) no sync9 ms synchronized method116 ms synchronized on this110 ms lock117 ms lock and finally113 ms

Design 2: Producer/Consumer 30 welcome socket Main thread Thread 2 Thread K Thread 1 Q: Dispatch queue main { void run { while (true) { Socket con = welcomeSocket.accept(); Q.add(con); } // end of while } WorkerThread { void run { while (true) { Socket myConnSock = Q.remove(); // process myConnSock myConnSock.close(); } // end of while } How to turn it into working code?

Main 31 main { void run { while (true) { Socket con = welcomeSocket.accept(); synchronized(Q) { Q.add(con); } } // end of while } main { void run { while (true) { Socket con = welcomeSocket.accept(); Q.add(con); } // end of while }

Worker 32 while (true) { // get next request Socket myConn = null; while (myConn==null) { synchronize(Q) { if (!Q.isEmpty()) myConn = (Socket) Q.remove(); } } // end of while // process myConn } WorkerThread { void run { while (true) { Socket myConnSock = Q.remove(); // process myConnSock myConnSock.close(); } // end of while }

Example r try m ShareQ/Server.java m ShareQ/ServiceThread.java 33

Problem of ShareQ Design r Thread continually spins (busy wait) until a condition holds r Can lead to high utilization and slow response time r Q: Does the shared welcomeSock have busy-wait? 34 while (true) { // spin lock; if (Q.condition) // { // do something } else { // do nothing } unlock } //end while

35 Outline r Admin and recap r High-performance network server design m Overview m Threaded servers Per-request thread Thread pool –Polling –Wait/notify

Solution: Suspension r Put thread to sleep to avoid busy spin r Thread life cycle: while a thread executes, it goes through a number of different phases m New: created but not yet started m Runnable: is running, or can run on a free CPU m Blocked: waiting for socket/I/O, a lock, or suspend (wait) m Sleeping: paused for a user-specified interval m Terminated: completed 36

Solution: Suspension r Thread stops execution until notified that the condition may be true 37 while (true) { // get next request Socket myConn = null; while (myConn==null) { lock Q; if (Q.isEmpty()) // { // stop and wait } else { // get myConn from Q } unlock Q; } // get the next request; process } Hold lock?

Alternative: Suspension r Thread stops execution until notified that the condition may be true 38 while (true) { // get next request Socket myConn = null; while (myConn==null) { lock Q; if (Q.isEmpty()) // { // stop and wait } else { // get myConn from Q } unlock Q; } // get the next request; process } Design pattern: - Need to release lock to avoid deadlock (to allow main thread write into Q) - Typically need to reacquire lock after waking up

Wait-sets and Notification r Every Java Object has an associated wait- set (called wait list) in addition to a lock object 39 object o o’s lock o’s wait list

Wait-sets and Notification r Wait list object can be manipulated only while the object lock is held Otherwise, IllegalMonitorStateException is thrown 40 object o o’s lock o’s wait list

Wait-sets  Thread enters the wait-set by invoking wait()  wait() releases the lock No other held locks are released m then the thread is suspended  Can add optional time wait(long millis)  wait() is equivalent to wait(0) – wait forever m for robust programs, it is typically a good idea to add a timer 41

Worker 42 while (true) { // get next request Socket myConn = null; synchronized(Q) { while (Q.isEmpty()) { Q.wait(); } myConn = Q.remove(); } // end of sync // process request in myConn } // end of while while (true) { // get next request Socket myConn = null; while (myConn==null) { lock Q; if (! Q.isEmpty()) // { myConn = Q.remove(); } unlock Q; } // end of while // get the next request; process } Note the while loop; no guarantee that Q is not empty when wake up

Wait-set and Notification (cont) r Threads are released from the wait-set when:  notifyAll() is invoked on the object All threads released (typically recommended)  notify() is invoked on the object One thread selected at ‘random’ for release m The specified time-out elapses  The thread has its interrupt() method invoked InterruptedException thrown m A spurious wakeup occurs Not (yet!) speç’ed but an inherited property of underlying synchronization mechanisms e.g., POSIX condition variables 43

Notification  Caller of notify() must hold lock associated with the object r Those threads awoken must reacquire lock before continuing m (This is part of the function; you don’t need to do it explicitly) m Can’t be acquired until notifying thread releases it m A released thread contends with all other threads for the lock 44

Main Thread 45 main { void run { while (true) { Socket con = welcomeSocket.accept(); synchronize(Q) { Q.add(con); Q.notifyAll(); } } // end of while } main { void run { while (true) { Socket con = welcomeSocket.accept(); synchronized(Q) { Q.add(con); } } // end of while } welcome socket Main thread Thread K Thread 1 Q: Dispatch queue

Suspend Worker 46 while (true) { // get next request Socket myConn = null; while (myConn==null) { synchronize(Q) { if (! Q.isEmpty()) // { myConn = Q.remove(); } else { Q.wait(); } } // end of while // process myConn } welcome socket Main thread Thread K Thread 1 Q: Dispatch queue while (true) { // get next request Socket myConn = null; while (myConn==null) { synchronize(Q) { if (! Q.isEmpty()) // { myConn = Q.remove(); } } } // end of while // process myConn } Busy wait

Worker: Another Format 47 while (true) { // get next request Socket myConn = null; synchronized(Q) { while (Q.isEmpty()) { Q.wait(); } myConn = Q.remove(); } // end of sync // process request in myConn } // end of while Note the while loop; no guarantee that Q is not empty when wake up

Example r See m WaitNotify/Server.java m WaitNotify/ServiceThread.java 48

Summary: Guardian via Suspension: Waiting 49 synchronized (obj) { while (!condition) { try { obj.wait(); } catch (InterruptedException ex) {... } } // end while // make use of condition } // end of sync r Golden rule: Always test a condition in a loop m Change of state may not be what you need m Condition may have changed again r Break the rule only after you are sure that it is safe to do so

Summary: Guarding via Suspension: Changing a Condition 50 synchronized (obj) { condition = true; obj.notifyAll(); // or obj.notify() }  Typically use notifyAll() r There are subtle issues using notify(), in particular when there is interrupt

Note r Use of wait(), notifyAll() and notify() similar to m Condition queues of classic Monitors m Condition variables of POSIX PThreads API m In C# it is called Monitor ( us/library/ms aspx) us/library/ms aspx r Python Thread module in its Standard Library is based on Java Thread model ( html) m “The design of this module is loosely based on Java’s threading model. However, where Java makes locks and condition variables basic behavior of every object, they are separate objects in Python. ” 51

Java (1.5) r Condition created from a Lock  await called with lock held m Releases the lock But not any other locks held by this thread m Adds this thread to wait set for lock m Blocks the thread  signallAll called with lock held m Resumes all threads on lock’s wait set m Those threads must reacquire lock before continuing (This is part of the function; you don’t need to do it explicitly) 52 interface Lock { Condition newCondition();... } interface Condition { void await(); void signalAll();... }

Producer/Consumer Example 53 Lock lock = new ReentrantLock(); Condition ready = lock.newCondition(); boolean valueReady = false; Object value; void produce(Object o) { lock.lock(); while (valueReady) ready.await(); value = o; valueReady = true; ready.signalAll(); lock.unlock(); } Object consume() { lock.lock(); while (!valueReady) ready.await(); Object o = value; valueReady = false; ready.signalAll(); lock.unlock(); }

Beyond Class: Complete Java Concurrency Framework Executors — Executor — ExecutorService — ScheduledExecutorService — Callable — Future — ScheduledFuture — Delayed — CompletionService — ThreadPoolExecutor — ScheduledThreadPoolExecutor — AbstractExecutorService — Executors — FutureTask — ExecutorCompletionService Queues — BlockingQueue — ConcurrentLinkedQueue — LinkedBlockingQueue — ArrayBlockingQueue — SynchronousQueue — PriorityBlockingQueue — DelayQueue 54 Concurrent Collections — ConcurrentMap — ConcurrentHashMap — CopyOnWriteArray{List,Set} Synchronizers — CountDownLatch — Semaphore — Exchanger — CyclicBarrier Locks: java.util.concurrent.locks — Lock — Condition — ReadWriteLock — AbstractQueuedSynchronizer — LockSupport — ReentrantLock — ReentrantReadWriteLock Atomics: java.util.concurrent.atomic — Atomic[Type] — Atomic[Type]Array — Atomic[Type]FieldUpdater — Atomic{Markable,Stampable}Reference See jcf slides for a tutorial.

Correctness r What do you analyze to show the server design is correct? 55 main { void run { while (true) { Socket con = welcomeSocket.accept(); synchronize(Q) { Q.add(con); Q.notifyAll(); } } // end of while } while (true) { // get next request Socket myConn = null; synchronized(Q) { while (Q.isEmpty()) { Q.wait(); } myConn = Q.remove(); } // end of sync // process request in myConn } // end of while

Key Correctness Properties r Safety r Liveness (progress) r Fairness m For example, in some settings, a designer may want the threads to share load equally 56

Safety Properties r What safety properties? m No read/write; write/write conflicts holding lock Q before reading or modifying shared data Q and Q.wait_list m Q.remove() is not on an empty queue r There are formal techniques to model server programs and analyze their properties, but we will use basic analysis m This is enough in many cases 57

Make Program Explicit 58 main { void run { while (true) { Socket con = welcomeSocket.accept(); synchronize(Q) { Q.add(con); Q.notifyAll(); } } // end of while } 1.main { void run { 2. while (true) { 3. Socket con = welcomeSocket.accept(); 4. lock(Q) { 5. Q.add(con); 6. notify Q.wait_list; // Q.notifyAll(); 7. unlock(Q); 8. } // end of while 9. }

59 while (true) { // get next request Socket myConn = null; synchronized(Q) { while (Q.isEmpty()) { Q.wait(); } myConn = Q.remove(); } // end of sync // process request in myConn } // end of while 1.while (true) { // get next request 2. Socket myConn = null; 3. lock(Q); 4. while (Q.isEmpty()) { 5. unlock(Q) 6. add to Q.wait_list; 7. yield until marked to wake; //wait 8. lock(Q); 9. } 10. myConn = Q.remove(); 11. unlock(Q); // process request in myConn 12.} // end of while

Statements to State 60 m4: lock 1.main { void run { 2. while (true) { 3. Socket con = welcomeSocket.accept(); 4. lock(Q) { 5. Q.add(con); 6. notify Q.wait_list; // Q.notifyAll(); 7. unlock(Q); 8. } // end of while 9. } m5: Q.add m6: Qwl.notify m7: unlock

Statements 61 1.while (true) { // get next request 2. Socket myConn = null; 3. lock(Q); 4. while (Q.isEmpty()) { 5. unlock(Q) 6. add to Q.wait_list; 7. yield; //wait 8. lock(Q); 9. } 10. myConn = Q.remove(); 11. unlock(Q); // process request in myConn 12.} // end of while s3: lock s4: Q.isEmpty s5: unlock s6: add Qwl s7: yield s8: lock s10: Q.remove s11: unlock

Check Safety 62 m4: lock m5: Q.add m6: Qwl.notify m7: unlock s3: lock s4: Q.isEmpty s5: unlock s6: add Qwl s7: yield s8: lock s10: Q.remove s11: unlock conflict

Real Implementation of wait 63 1.while (true) { // get next request 2.Socket myConn = null; 3. lock(Q); 4. while (Q.isEmpty()) { 5. add to Q.wait_list; 6. unlock(Q); after add to wait list 7. yield; //wait 8. lock(Q); 9. } 10. myConn = Q.remove(); 11. unlock(Q); // process request in myConn 12.} // end of while

States 64 m4: lock m5: Q.add m6: Qwl.notify m7: unlock s3: lock s4: Q.isEmpty s6’: unlock s5’: add Qwl s7: yield s8: lock s10: Q.remove s11: unlock

Liveness Properties r What liveness (progress) properties? m main thread can always add to Q m every connection in Q will be processed 65

Main Thread can always add to Q r Assume main is blocked r Suppose Q is not empty, then each iteration removes one element from Q r In finite number of iterations, all elements in Q are removed and all service threads unlock and block 66 s3: lock s4: Q.isEmpty s6’: unlock s5’: add Q.wl s7: yield s8: lock s10: Q.remove s11: unlock

Each connection in Q is processed r Cannot be guaranteed unless m there is fairness in the thread scheduler, or m put a limit on Q size to block the main thread 67

Blocking Queues in Java r Design Pattern for producer/consumer pattern with blocking, e.g., m put/take r Two handy implementations m LinkedBlockingQueue (FIFO, may be bounded) m ArrayBlockingQueue (FIFO, bounded) m (plus a couple more) 68 /BlockingQueue.html