Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Request in a QUIC way @shibuya.apk#28

TakuSemba
September 27, 2018

Request in a QUIC way @shibuya.apk#28

TakuSemba

September 27, 2018
Tweet

More Decks by TakuSemba

Other Decks in Technology

Transcript

  1. View Slide

  2. @takusemba
    https://github.com/TakuSemba

    View Slide

  3. QUIC?

    View Slide

  4. Quick UDP Internet Connections

    View Slide

  5. QUIC

    View Slide

  6. Google QUIC
    https://www.chromium.org/quic

    View Slide

  7. QUIC for IETF
    https://tools.ietf.org/html/draft-hamilton-early-deployment-quic-00

    View Slide

  8. Merits

    View Slide

  9. Merits
    ɾConnection establishment latency

    View Slide

  10. Connection establishment latency
    Client Server

    View Slide

  11. Connection establishment latency
    TCP
    Client Server

    View Slide

  12. Connection establishment latency
    TCP
    Client Server

    View Slide

  13. Connection establishment latency
    Client Server
    TCP + TLS

    View Slide

  14. Connection establishment latency
    TCP + TLS
    Client Server

    View Slide

  15. Connection establishment latency
    TCP + TLS
    Client Server
    1-3 roundtrips

    View Slide

  16. Connection establishment latency
    TCP + TLS
    Application Data
    Client Server
    1-3 roundtrips

    View Slide

  17. Connection establishment latency
    QUIC
    Client Server

    View Slide

  18. Connection establishment latency
    QUIC
    Client Server

    View Slide

  19. Connection establishment latency
    QUIC
    Client Server
    0-1 roundtrips

    View Slide

  20. Connection establishment latency
    QUIC
    Application Data
    Client Server
    0-1 roundtrips

    View Slide

  21. Merits
    ɾConnection establishment latency

    View Slide

  22. Merits
    ɾConnection establishment latency
    ɾMultiplexing

    View Slide

  23. Multiplexing
    TCP
    Client Server

    View Slide

  24. Multiplexing
    TCP
    Client Server

    View Slide

  25. Multiplexing
    TCP
    head of line blocking
    Client Server

    View Slide

  26. Multiplexing
    QUIC
    stream 1
    stream 2
    stream 3
    Client Server

    View Slide

  27. Multiplexing
    QUIC
    stream 1
    stream 2
    stream 3
    Client Server

    View Slide

  28. Multiplexing
    QUIC


    stream 1
    stream 2
    stream 3
    Client Server

    View Slide

  29. Merits
    ɾConnection establishment latency
    ɾMultiplexing

    View Slide

  30. Merits
    ɾConnection establishment latency
    ɾMultiplexing
    ɾConnection Migration

    View Slide

  31. Connection Migration
    TCP
    IP: yyy.yyy.yyy.yyy
    Port: bb
    IP: xxx.xxx.xxx.xxx
    Port: aa
    Client Server

    View Slide

  32. Connection Migration
    TCP
    IP: yyy.yyy.yyy.yyy
    Port: bb
    IP: zzz.zzz.zzz.zzz
    Port: cc
    Client Server

    View Slide

  33. Connection Migration
    QUIC
    Connection ID: xxxxxx Connection ID: yyyyyy
    Client Server

    View Slide

  34. Connection Migration
    QUIC
    Connection ID: xxxxxx Connection ID: yyyyyy
    Client Server

    View Slide

  35. Merits
    ɾConnection establishment latency
    ɾMultiplexing
    ɾConnection Migration

    View Slide

  36. Merits
    ɾConnection establishment latency
    ɾMultiplexing
    ɾConnection Migration
    ɾCongestion Control

    View Slide

  37. Merits
    ɾConnection establishment latency
    ɾMultiplexing
    ɾConnection Migration
    ɾCongestion Control
    ɾForward Error Correction

    View Slide

  38. Cronet

    View Slide

  39. https://developer.android.com/guide/topics/connectivity/cronet

    View Slide

  40. Quicstart

    View Slide

  41. dependencies {

    implementation "org.chromium.net:cronet-embedded:x.x.x"

    }

    View Slide

  42. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()

    View Slide

  43. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()
    .enableQuic(true)

    View Slide

  44. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()

    View Slide

  45. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()
    newUrlRequestBuilder(url, callback, executor)

    View Slide

  46. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()
    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    View Slide

  47. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()

    View Slide

  48. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()

    View Slide

  49. val cronetEngine = CronetEngine.Builder(context)

    .enableHttp2(true)

    .enableQuic(true)

    .build()
    val request = cronetEngine.newUrlRequestBuilder(url, callback, executor)

    .setHttpMethod("GET")

    .addHeader("hoge", "huga")

    .build()
    request.start()
    callback

    View Slide

  50. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {

    // read response

    request.read(ByteBuffer.allocateDirect(32 * 1024))

    }



    }

    View Slide

  51. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {

    // read response

    request.read(ByteBuffer.allocateDirect(32 * 1024))

    }



    }
    override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {

    // read response

    request.read(ByteBuffer.allocateDirect(32 * 1024))

    }

    View Slide

  52. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }



    }

    View Slide

  53. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }



    }
    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }

    View Slide

  54. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }



    }
    override fun onReadCompleted(

    byteBuffer: ByteBuffer

    View Slide

  55. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }



    }
    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    }

    View Slide

  56. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }



    }
    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }

    View Slide

  57. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }



    }
    override fun onReadCompleted(

    request: UrlRequest,

    info: UrlResponseInfo,

    byteBuffer: ByteBuffer) {

    // write response

    byteBuffer.flip()

    receiveChannel.write(byteBuffer)

    // read response

    byteBuffer.clear()

    request.read(byteBuffer)

    }

    View Slide

  58. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {

    // succeeded

    val result = bytesReceived.toByteArray()

    }



    }

    View Slide

  59. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {

    // succeeded

    val result = bytesReceived.toByteArray()

    }



    }
    override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {

    // succeeded

    val result = bytesReceived.toByteArray()

    }

    View Slide

  60. val callback = object : UrlRequest.Callback() {

    private val bytesReceived = ByteArrayOutputStream()

    private val receiveChannel = Channels.newChannel(bytesReceived)

    override fun onFailed(request: UrlRequest, info: UrlResponseInfo, e: CronetException) {

    // failed

    Log.d("CRONET_SAMPLE", "failed: ${e.message}")

    }



    }
    override fun onFailed(request: UrlRequest, info: UrlResponseInfo, e: CronetException) {

    // failed

    Log.d("CRONET_SAMPLE", "failed: ${e.message}")

    }

    View Slide

  61. QUIC for ExoPlayer

    View Slide

  62. https://github.com/google/ExoPlayer/tree/release-v2/extensions/cronet

    View Slide

  63. Client
    .m3u8 .mp4
    .mp4
    .ts
    OkHttp

    View Slide

  64. Client
    .m3u8 .mp4
    .mp4
    .ts
    Cronet

    View Slide

  65. OkHttpClient

    View Slide

  66. val userAgent = "takusemba"

    val okHttpClient = OkHttpClient()

    val transferListener = DefaultBandwidthMeter()

    val factory = OkHttpDataSourceFactory(okHttpClient, userAgent, transferListener)
    OkHttpClient

    View Slide

  67. val userAgent = "takusemba"

    val okHttpClient = OkHttpClient()

    val transferListener = DefaultBandwidthMeter()

    val factory = OkHttpDataSourceFactory(okHttpClient, userAgent, transferListener)
    OkHttpClient
    Cronet

    View Slide

  68. val userAgent = "takusemba"

    val okHttpClient = OkHttpClient()

    val transferListener = DefaultBandwidthMeter()

    val factory = OkHttpDataSourceFactory(okHttpClient, userAgent, transferListener)
    OkHttpClient
    val userAgent = "takusemba"

    val cronetEngine = CronetEngine.Builder(context).enableQuic(true).build()

    val wrapper = CronetEngineWrapper(cronetEngine)

    val executor = Executors.newSingleThreadExecutor()

    val predicate = Predicate { contentType: String -> true }
    val factory = CronetDataSourceFactory(wrapper, executor, predicate, userAgent)
    Cronet

    View Slide

  69. val userAgent = "takusemba"

    val okHttpClient = OkHttpClient()

    val transferListener = DefaultBandwidthMeter()

    val factory = OkHttpDataSourceFactory(okHttpClient, userAgent, transferListener)
    OkHttpClient
    val userAgent = "takusemba"

    val cronetEngine = CronetEngine.Builder(context).enableQuic(true).build()

    val wrapper = CronetEngineWrapper(cronetEngine)

    val executor = Executors.newSingleThreadExecutor()

    val predicate = Predicate { contentType: String -> true }
    val factory = CronetDataSourceFactory(wrapper, executor, predicate, userAgent)
    val wrapper = CronetEngineWrapper(cronetEngine)

    val executor = Executors.newSingleThreadExecutor()

    val predicate = Predicate { contentType: String -> true }
    Cronet

    View Slide

  70. val userAgent = "takusemba"

    val okHttpClient = OkHttpClient()

    val transferListener = DefaultBandwidthMeter()

    val factory = OkHttpDataSourceFactory(okHttpClient, userAgent, transferListener)
    OkHttpClient
    Cronet
    val userAgent = "takusemba"

    val cronetEngine = CronetEngine.Builder(context).enableQuic(true).build()

    val wrapper = CronetEngineWrapper(cronetEngine)

    val executor = Executors.newSingleThreadExecutor()

    val predicate = Predicate { contentType: String -> true }
    val factory = CronetDataSourceFactory(wrapper, executor, predicate, userAgent)
    val factory = CronetDataSourceFactory(wrapper, executor, predicate, userAgent)

    View Slide

  71. View Slide

  72. https://github.com/TakuSemba/QuicPlayer
    Sample App

    View Slide

  73. https://github.com/takusemba
    https://twitter.com/takusemba
    Request in a QUIC way

    View Slide