Async Concurrent HTTP Apps in Java

100

description

Async Concurrent HTTP Apps in JavaCON3712 Landman from JavaOne 2014

Transcript of Async Concurrent HTTP Apps in Java

Page 1: Async Concurrent HTTP Apps in Java
Page 2: Async Concurrent HTTP Apps in Java
Page 3: Async Concurrent HTTP Apps in Java
Page 4: Async Concurrent HTTP Apps in Java
Page 5: Async Concurrent HTTP Apps in Java

@_yoav_

github.com/yoav

cee-tee-oh@jfrog

Page 6: Async Concurrent HTTP Apps in Java
Page 7: Async Concurrent HTTP Apps in Java
Page 8: Async Concurrent HTTP Apps in Java
Page 9: Async Concurrent HTTP Apps in Java
Page 10: Async Concurrent HTTP Apps in Java
Page 11: Async Concurrent HTTP Apps in Java
Page 12: Async Concurrent HTTP Apps in Java

REQUIREMENTS

–  parallel file Downloads

–  Parallel Download parts

–  interrupt/pause/resume

–  Progress events

–  Checksum caching

Page 13: Async Concurrent HTTP Apps in Java
Page 14: Async Concurrent HTTP Apps in Java
Page 15: Async Concurrent HTTP Apps in Java
Page 16: Async Concurrent HTTP Apps in Java
Page 17: Async Concurrent HTTP Apps in Java

LET’S LOOK IF WE CAN USE IT!

1.  No traceable license 2. No website or docs 3. No traceable sources 4. It’s an app, not a lib

Page 18: Async Concurrent HTTP Apps in Java
Page 19: Async Concurrent HTTP Apps in Java
Page 20: Async Concurrent HTTP Apps in Java

JAVA.NET.URLCONNECTION

1.  Memory wasteful (buffering)

2.  Minimal API

3.  Blocking streams

Page 21: Async Concurrent HTTP Apps in Java
Page 22: Async Concurrent HTTP Apps in Java

WHAT WE’RE LOOKING FOR

1.  Async/non-blocking

2.  Event callbacks

Page 23: Async Concurrent HTTP Apps in Java

WHAT IS IT GOING TO TAKE

1.  Reactor

2.  nio

Page 24: Async Concurrent HTTP Apps in Java
Page 25: Async Concurrent HTTP Apps in Java

– pattern for lightweight concurrency

– Event driven

– Threads reuse

– Uses non-blocking Io

Page 26: Async Concurrent HTTP Apps in Java

h"p://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-­‐siemens.pdf  

Page 27: Async Concurrent HTTP Apps in Java

h"p://gee.cs.oswego.edu/dl/cpjslides/nio.pdf  

Page 28: Async Concurrent HTTP Apps in Java

In Java, Reactor means NIO

Page 29: Async Concurrent HTTP Apps in Java
Page 30: Async Concurrent HTTP Apps in Java

SocketChannel channel= SocketChannel.open();!socketChannel.connect(new! InetSocketAddress("http://remote.com", 80));!...!Selector selector = Selector.open();!channel.configureBlocking(false);!SelectionKey k = channel.register(selector,! SelectionKey.OP_READ);!k.attach(handler);!!

Page 31: Async Concurrent HTTP Apps in Java

while (!Thread.interrupted()) {!selector.select();!Set selected = selector.selectedKeys();!Iterator it = selected.iterator();!while (it.hasNext())! SelectionKey k = (SelectionKey)(it.next();! ((Runnable)(k.attachment())).run();! selected.clear();!

}!

Page 32: Async Concurrent HTTP Apps in Java
Page 33: Async Concurrent HTTP Apps in Java
Page 34: Async Concurrent HTTP Apps in Java

NIO LIBRARIES

– Most of them are servers – Netty, grizzly, etc.

– Apache Mina – Apache HTTP components asyncclient – Ning http client

Page 35: Async Concurrent HTTP Apps in Java

– Client and server nio library

– Evolved from netty

– Latest release October 2012

Page 36: Async Concurrent HTTP Apps in Java
Page 37: Async Concurrent HTTP Apps in Java

NIO LIBRARIES

– Most of them are servers – Netty, grizzly, etc

– Apache Mina – Apache HTTP components asyncclient – Ning http client

Page 38: Async Concurrent HTTP Apps in Java
Page 39: Async Concurrent HTTP Apps in Java
Page 40: Async Concurrent HTTP Apps in Java
Page 41: Async Concurrent HTTP Apps in Java
Page 42: Async Concurrent HTTP Apps in Java
Page 43: Async Concurrent HTTP Apps in Java

try  (AsyncHttpClient  asyncHttpClient  =  new  AsyncHttpClient())  {          ListenableFuture<Response>  future  =  asyncHttpClient                          .prepareGet("http://oss.jfrog.org/api/system/ping")                          .execute(new  AsyncCompletionHandler<Response>()  {                                    @Override                                  public  Response  onCompleted(Response  response)  {                                          System.out.println(response.getResponseBody());                                          return  response;                                  }                                    @Override                                  public  void  onThrowable(Throwable  t)  {                                          t.printStackTrace();                                  }                          });          Response  response  =  future.get();  }  

Page 44: Async Concurrent HTTP Apps in Java
Page 45: Async Concurrent HTTP Apps in Java

• Request producer • Generates a request message and stream out its

content without buffering it in memory • Response consumer • Processes a response message without buffering its

content in memory

Page 46: Async Concurrent HTTP Apps in Java

try$(CloseableHttpAsyncClient1asyncHttpClient1=1HttpAsyncClients.createDefault())1{11111asyncHttpClient.start();11111Future<HttpResponse>1future1=1asyncHttpClient.execute(1111111111111HttpAsyncMethods.createGet("http://oss.jfrog.org/api/system/ping"),1111111111111new$AsyncByteConsumer<HttpResponse>()1{111111111111111111@Override11111111111111111protected$void$onResponseReceived(final$HttpResponse1response)1{111111111111111111111System.out.println(response.getStatusLine().getReasonPhrase());11111111111111111}111111111111111111@Override11111111111111111protected$void$onByteReceived(final$CharBuffer1buf,1final$IOControl1ioctrl)1{1}111111111111111111@Override11111111111111111protected$void$releaseResources()1{1}111111111111111111@Override11111111111111111protected$HttpResponse1buildResult(final$HttpContext1context)1{111111111111111111111return$(HttpResponse)1context.getAttribute("http.response");11111111111111111}11111111111111},1null);1111HttpResponse1response1=1future.get();1}1

Page 47: Async Concurrent HTTP Apps in Java
Page 48: Async Concurrent HTTP Apps in Java
Page 49: Async Concurrent HTTP Apps in Java

"All problems in computer science can be solved by another level of indirection"

David Wheeler

Page 50: Async Concurrent HTTP Apps in Java

public  interface  HttpProviderDownloadHandler  {            void  onResponseReceived(int  statusCode,  Map<String,  List<String>>  headers);            boolean  onBytesReceived(ByteBuffer  buf);            void  onFailed(Throwable  error);            void  onCanceled();            void  onCompleted();  }  

Page 51: Async Concurrent HTTP Apps in Java

Feature/Library Ning  client H3p  Async  Client Maturity Good Very  new  (early  2014) Download  cancela=on Easy With  bugs Progress  hooks Events  not  granular  

enough Just  use  onByteReceived()

Documenta=on A  bit  sparse Minimal Server-­‐side  counterpart None,  client  only org.apache.h"pcomponents  

h"pcore-­‐nio  

Page 52: Async Concurrent HTTP Apps in Java

0  100  200  300  400  500  600  700  800  900  

Small  file   Medium  file   Large  file  

Ning  

AHAC  

h"p://blogs.atlassian.com/2013/07/h"p-­‐client-­‐performance-­‐io/  

Page 53: Async Concurrent HTTP Apps in Java
Page 54: Async Concurrent HTTP Apps in Java
Page 55: Async Concurrent HTTP Apps in Java
Page 56: Async Concurrent HTTP Apps in Java
Page 57: Async Concurrent HTTP Apps in Java

And that one for discovering that range header is lost on redirect

Page 58: Async Concurrent HTTP Apps in Java
Page 59: Async Concurrent HTTP Apps in Java
Page 60: Async Concurrent HTTP Apps in Java
Page 61: Async Concurrent HTTP Apps in Java
Page 62: Async Concurrent HTTP Apps in Java

h"ps://github.com/h"p2/h"p2-­‐spec/issues/46  

Page 63: Async Concurrent HTTP Apps in Java
Page 64: Async Concurrent HTTP Apps in Java

HttpAsyncClientBuilder  builder  =  HttpAsyncClients.custom();  //  add  redirect  strategy  that  copies  "range"  headers,  if  exist  builder.setRedirectStrategy(new  DefaultRedirectStrategy()  {  

 @Override    public  HttpUriRequest  getRedirect(HttpRequest  request,  HttpResponse  response,        HttpContext  context)    HttpUriRequest  redirectRequest  =  super.getRedirect(request,  response,  context);    //  copy  "Range"  headers,  if  exist    Header[]  rangeHeaders  =  request.getHeaders(HttpHeaders.RANGE);    if  (rangeHeaders  !=  null)  {      for  (Header  header  :  rangeHeaders)  {        redirectRequest.addHeader(header);      }    }    return  redirectRequest;  

}});  

Page 65: Async Concurrent HTTP Apps in Java
Page 66: Async Concurrent HTTP Apps in Java
Page 67: Async Concurrent HTTP Apps in Java
Page 68: Async Concurrent HTTP Apps in Java
Page 69: Async Concurrent HTTP Apps in Java
Page 70: Async Concurrent HTTP Apps in Java

public  sta=c  String  encodeUrl(String  urlStr)    {          URLEncoder.encode(urlStr,  "UTF-­‐8");          ...  }  

Page 71: Async Concurrent HTTP Apps in Java
Page 72: Async Concurrent HTTP Apps in Java

“Utility class for HTML form encoding. This class contains static methods for converting a String to the application/x-www-form-urlencoded MIME format. For more information about HTML form encoding, consult the HTML specification.”

Page 73: Async Concurrent HTTP Apps in Java
Page 74: Async Concurrent HTTP Apps in Java
Page 75: Async Concurrent HTTP Apps in Java
Page 76: Async Concurrent HTTP Apps in Java
Page 77: Async Concurrent HTTP Apps in Java

h"p://www.safaribooksonline.com/library/view/h"p-­‐the-­‐definiave/1565925092/ch04s07.html  

Page 78: Async Concurrent HTTP Apps in Java
Page 79: Async Concurrent HTTP Apps in Java
Page 80: Async Concurrent HTTP Apps in Java
Page 81: Async Concurrent HTTP Apps in Java
Page 82: Async Concurrent HTTP Apps in Java
Page 83: Async Concurrent HTTP Apps in Java

– Write to separate files, combine on finish

– Write to same file, seeking to the right position

Page 84: Async Concurrent HTTP Apps in Java
Page 85: Async Concurrent HTTP Apps in Java
Page 86: Async Concurrent HTTP Apps in Java

• Implements SeekableByteChannel  

java.nio.channels.FileChannel#write(                  java.nio.ByteBuffer  src,  long  position)  

Page 87: Async Concurrent HTTP Apps in Java

• PersistentFileProgressInfo • Save the total size, sha1, number of parts • State of each part (offset, size, completed...)  

FileProgressInfo   FilePartProgressInfo  *  

Page 88: Async Concurrent HTTP Apps in Java
Page 89: Async Concurrent HTTP Apps in Java

• VM level • O/S level

Page 90: Async Concurrent HTTP Apps in Java
Page 91: Async Concurrent HTTP Apps in Java

• Prevent same VM threads writing to the file when we started closing it • Closing sequence: • Release file locks • Close channels • Rename a file to it's final name (remove .part) • Erase progress info

Page 92: Async Concurrent HTTP Apps in Java

ReentrantReadWriteLock.ReadLock  writeToFileLock  =  rwl.readLock();  ReentrantReadWriteLock.WriteLock  closeFileLock  =  rwl.writeLock();    public  void  close()  throws  IOException  {                  this.closeFileLock.lock();  }    public  int  write(int  partIndex,  ByteBuffer  buf)  {          if  (!this.writeToFileLock.tryLock())  {                  throw  new  IllegalStateException("File  is  being  closed");          }          ...  }  

Page 93: Async Concurrent HTTP Apps in Java

• Multiple downloader instances writing to the same file • Needed for writing: • Partial download file • Persistent download progress

Page 94: Async Concurrent HTTP Apps in Java

FileLock  lock  =  fileChannel.tryLock();                                  //Non-­‐shared:  (0L,  Long.MAX_VALUE,  false)            if  (lock  ==  null)  {                  throw  new  OverlappingFileLockException();          }          return  lock;  }  

Page 95: Async Concurrent HTTP Apps in Java

private  FileLock  lock(FileChannel  fileChannel)  throws  IOException  {          FileLock  lock  =  fileChannel.tryLock(Long.MAX_VALUE  -­‐  1,  1,  false);          if  (lock  ==  null)  {                  throw  new  OverlappingFileLockException();          }          return  lock;  }  

WTF?!  

Page 96: Async Concurrent HTTP Apps in Java
Page 97: Async Concurrent HTTP Apps in Java

HTTP/2

–  Mostly standardizing Google's spdy

–  Header compression –  multiplexing (framing) –  prioritization –  On the way clears some

ambiguities –  E.g. compressed content length

Page 98: Async Concurrent HTTP Apps in Java

h"p://chimera.labs.oreilly.com/books/1230000000545/ch12.html#REQUEST_RESPONSE_MULTIPLEXING  

Page 99: Async Concurrent HTTP Apps in Java

• RTFM: RFC 2616 • Ultimate book: HTTP: The Definitive Guide • Amazon • Safari

• Reactor pattern • Doug Lea on NIO

Page 100: Async Concurrent HTTP Apps in Java