$30 off During Our Annual Pro Sale. View Details »

Fast & Functional (Scala Matsuri, JP)

Fast & Functional (Scala Matsuri, JP)

In this talk we are going to create a functional and blazingly fast microservice. We will use functional programming abstractions to quickly mix & match different HTTP libraries, state implementations and concurrency configurations. Each step will be followed by a performance analysis using different tools from JVM toolbox. This talk is for you if you want to see how cats IO monad, async-profiler, flame graphs and wrk are used together to create microseconds-fast Scala service for YouTube videos statistics.

Michał Płachta

June 29, 2019
Tweet

More Decks by Michał Płachta

Other Decks in Programming

Transcript

  1. @miciek
    AST &
    UNCTIONAL
    F
    F
    Room A, 14:00
    In this talk we are going to create
    a functional and blazingly fast
    microservice in Scala. We will use
    f u n c t i o n a l p r o g r a m m i n g
    abstractions to quickly mix &
    match different HTTP libraries,
    state implementations and
    concurrency configurations. Each
    step will be followed by a
    performance analysis using
    different tools from JVM toolbox.

    View Slide

  2. @miciek
    λ
    Michał Płachta
    www.michalplachta.com
    @miciek
    AST &
    UNCTIONAL
    F
    F

    View Slide

  3. @miciek
    Hello, I’d like to hear a
    functional programming joke
    関数型プログラミングの冗談を聴いたことがある

    View Slide

  4. @miciek
    OK. Why did the chicken
    cross the road?
    functional programming joke
    どうしてニワトリは道路路を渡るの?

    View Slide

  5. @miciek
    cross the road?
    I don’t know. Why?
    分かりません。どうしてでしょう?

    View Slide

  6. @miciek
    It’s very simple really.
    I don’t know. Why?
    それは本当にとても簡単です。

    View Slide

  7. @miciek
    The best way to understand
    it comes from the idea of
    contravariant functor.
    It’s very simple really.
    理理解するための最良の⽅方法は、
    反変ファンクターの考えから来ています。

    View Slide

  8. @miciek
    As you probably know, a functor is just a
    mapping between categories that respects the
    category structure; a homomorphism, if you
    will.
    contravariant functor.
    ファンクターは圏の構造を保った写像で、
    準同型写像とも⾔言われます

    View Slide

  9. @miciek
    Now, some constructions that we want to
    express look like functors but in some sense
    “turn morphisms around”. We call these
    contravariant functors.
    will.
    さて、私たちが表現したいいくつかの構造はファンクタのように⾒見見えます
    が、ある意味では「変形を逆転させる」のです。私たちはこれらの反変ファ
    ンクタと呼びます。

    View Slide

  10. @miciek
    As you have probably noticed, we can indeed define a
    contravariant functor as simply a covariant functor on opposite
    categories, invoking the obvious correspondence. Of course you
    have already noticed the obvious connection this has with the
    category theoretic generalization of topological presheaves — a
    presheaf on a topology is just a contravariant functor from the…
    私たちは反変ファンクターを単に逆圏の共変ファンクターとして定義しなお
    すことができます。もちろん、これが圏論的なトポロジカルなプリシーフの
    ⼀一般化に関連していることにすでにお分かりですね (以下延々

    View Slide

  11. @miciek
    私は Haskell の冗談を聞きたいです。

    View Slide

  12. @miciek
    AST &
    UNCTIONAL
    F
    F

    View Slide

  13. @miciek
    UNCTIONAL
    F
    very modular
    plug & play
    using functional mechanics
    quickly replacing modules
    without affecting the logic
    simple real-world
    service in Scala
    モジュール性、プラグアンドプレイ

    View Slide

  14. @miciek
    F
    1st meaning:
    PERFORMANCE
    AST
    Fast の第⼀一義は、実⾏行行速度

    View Slide

  15. @miciek
    F
    2nd meaning:
    DEV SPEED
    AST
    very modular
    plug & play
    Fast の第⼆二義は、開発速度

    View Slide

  16. @miciek
    In this talk…
    AST &
    UNCTIONAL
    F
    F
    modularity (the λ way!)
    plug & play
    simple real-world
    service in Scala

    View Slide

  17. @miciek
    Influencer Stats
    インフルエンサーの統計情報

    View Slide

  18. @miciek
    We need a marketing strategy
    for our product!
    Marketing
    マーケティング

    View Slide

  19. @miciek
    Remember when…
    Old Ways Don’t Work
    …people watched TV
    みんながテレビを⾒見見ていた時代の古いやり⽅方は通⽤用しない

    View Slide

  20. @miciek
    Influencers
    22 237 likes 2302 likes, 70 retweets
    201 232 views, 23987 likes 502 123 views, 2012 likes
    …and more
    今のインフルエンサー

    View Slide

  21. @miciek
    Influencers items aggregation
    1 201 882 views, 423 987 likes
    …and more
    All tweets, youtube videos, etc for one product
    ⼀一つのプロダクトに関して全てのアイテムを集約

    View Slide

  22. @miciek
    Influencer Stats service
    collection of videos
    how many total views
    how many total likes
    動画、PV、like 数など

    View Slide

  23. @miciek
    Requirement #1
    Collections
    ability to
    add & update
    Collections of videos

    COLLECTION 1

    COLLECTION 2
    要件1: 動画のコレクションを作成、更更新できること

    View Slide

  24. @miciek
    Requirement #2
    Fetch YouTube Stats
    ability to
    fetch individual video
    stats through
    YouTube API
    YouTube
    API
    20 views, 2 likes
    要件2: 個々の動画に関して統計を取得できること

    View Slide

  25. @miciek
    Requirement #3
    Calculate Stats
    ability to
    calculate & return
    Collection statistics

    1 201 882 views, 423 987 likes
    要件3: コレクション全体の統計情報を集計できること

    View Slide

  26. @miciek
    Non-functional
    requirements
    ✓HTTP Web Server
    ✓HTTP Client
    ✓Collection Storage
    ✓Logging
    ⾮非機能要件

    View Slide

  27. @miciek
    PURE Side-effect’y
    f
    input value output value
    f
    input value


    hard to keep separate
    hard to test
    easy to keep separate
    easy to test
    副作⽤用はテストしづらい

    View Slide

  28. @miciek
    PURE
    ✓Save & Load Collections
    ✓Fetch YouTube Stats
    ✓HTTP Web Server
    ✓HTTP Client
    ✓Collection storage
    ✓Logging
    Side-effect’y
    ✓Calculate Stats
    f
    video #1 stats
    video #2 stats
    aggregated stats
    とは⾔言っても機能の多くは副作⽤用を伴う

    View Slide

  29. @miciek
    PURE
    ✓Save & Load Collections
    ✓Fetch YouTube Stats
    ✓HTTP Web Server
    ✓HTTP Client
    ✓Collection storage
    ✓Logging
    Side-effect’y
    ✓Calculate Stats
    ULTIMATE GOAL
    move as much as we
    can to the PURE side
    できる限り多くの機能を pure 側へと移⾏行行させる

    View Slide

  30. @miciek
    ULTIMATE GOAL
    move as much as we
    can to the PURE side
    できる限り多くの機能を pure 側へと移⾏行行させる

    View Slide

  31. @miciek
    ULTIMATE GOAL
    move as much as we
    can to the PURE side
    to test in isolation
    to reason in isolation
    to easily swap components
    (because they are isolated)
    隔離された単体でテストしたり、論理理的に振る舞いを分析したり、
    コンポーネントを差し替えるのが容易易な状態になるのが究極の⽬目標

    View Slide

  32. @miciek
    What happens next…
    intro
    code
    Java code
    performance
    tests
    t
    we are
    here

    View Slide

  33. @miciek
    Modular programming
    using algebras
    代数を利利⽤用したモジュラープログラミング

    View Slide

  34. @miciek
    Model
    e.g.
    -a YouTube video
    -instagram post
    -tweet
    Model の実装を考える

    View Slide

  35. @miciek
    Pure logic
    f
    video #1 stats
    video #2 stats
    aggregated stats
    純粋なロジック

    View Slide

  36. @miciek
    Pure logic

    View Slide

  37. @miciek
    Pure logic

    View Slide

  38. @miciek
    Pure logic

    1 201 882 views, 423 987 likes
    easy to test
    easy to reason about
    PURE WIN!

    View Slide

  39. @miciek
    Can it be as easy as this?
    f
    input value output value
    NOPE
    では次のような関数は?

    View Slide

  40. @miciek
    Can it be as easy as this?
    1. get collection collectionId
    2. get videoIds from it
    3. for each videoId, call YouTube API
    4.call our pure calculate function
    (and log some things in between)



    f
    input value output value
    f
    input value output value
    いくつか問題があります。

    View Slide

  41. @miciek
    Can it be as easy as this?
    1. get collection collectionId
    2. get videoIds from it
    3. for each videoId, call YouTube API
    4. call our calculate function
    NOPE
    because side effects




    副作⽤用があるからです。

    View Slide

  42. @miciek
    Side-effect’y stuff

    View Slide

  43. @miciek
    Side-effect’y stuff
    1. get collection collectionId
    2. get videoIds from it
    3. for each videoId, call YouTube API
    4. call our pure calculate function

    View Slide

  44. @miciek
    Side-effect’y stuff
    1. get collection collectionId
    2. get videoIds from it
    3. for each videoId, call YouTube API
    4. call our pure calculate function

    View Slide

  45. @miciek
    Specific effect type
    特定の作⽤用を表す型が使われています。

    View Slide

  46. @miciek
    Too powerful effect type :(
    作⽤用型が強すぎます。

    View Slide

  47. @miciek
    Side-effect’y stuff
    1. get collection collectionId
    2. get videoIds from it
    3. for each videoId, call YouTube API
    4. call our pure calculate function
    F doesn’t do anything
    F is chosen by the user
    モナドの F とだけ弱く指定します。

    View Slide

  48. @miciek
    synchronous
    asynchronous
    IO effect type
    F[_]

    View Slide

  49. @miciek
    Constrained?
    A doesn’t do anything
    A is chosen by the user

    View Slide

  50. @miciek
    Constrained?
    A doesn’t do anything
    A is chosen by the user

    View Slide

  51. @miciek
    We can’t constrain ourselves
    What we have
    What we want
    F doesn’t do anything
    F is chosen by the user
    制限を後付けすることはできません。

    View Slide

  52. @miciek
    Constraints Liberate
    F doesn’t do anything
    F is chosen by the user
    Constraints Liberate
    Liberties Constrain
    制限は解放し、⾃自由は制限する

    View Slide

  53. @miciek
    Get collection collectionId

    View Slide

  54. @miciek
    Get collection collectionId
    just an algebra

    View Slide

  55. @miciek
    Get videoIds from it

    View Slide

  56. @miciek
    For each videoId call YouTube API

    View Slide

  57. @miciek
    For each videoId call YouTube API

    View Slide

  58. @miciek
    Call our pure calculate function

    View Slide

  59. @miciek
    (and log some things in between)

    View Slide

  60. @miciek
    (and log some things in between)

    View Slide

  61. @miciek
    Signature is enough

    View Slide

  62. @miciek

    View Slide

  63. @miciek
    PURE
    ✓Collections interpreter
    ✓HTTP Web Server
    ✓HTTP Client interpreter
    ✓Collection storage interpreter
    ✓Logging interpreter
    Side-effect’y
    ✓Calculate Stats
    ✓Collections algebra
    ✓HTTP Client algebra
    ✓Logging algebra
    ✓getStats algorithm on F

    View Slide

  64. @miciek
    algebras
    ✓Collections interpreter
    ✓HTTP Client interpreter
    ✓Collection storage interpreter
    ✓Logging interpreter
    interpreters
    ✓Collections algebra
    ✓HTTP Client algebra
    ✓Logging algebra
    代数 | インタプリタ

    View Slide

  65. @miciek
    algebra
    interpreter

    View Slide

  66. @miciek
    What happens next…
    intro
    code
    Java code
    performance
    tests
    t
    we are
    here

    View Slide

  67. @miciek
    algebra interpreters
    - AkkaHttp
    - Hammock (Apache)
    - Http4s
    - InMem LinkedList
    - InMem TrieMap
    - Log All
    - Max 1k/sec (dropping rest)
    plug & play
    代数 | インタプリタ

    View Slide

  68. @miciek
    Make it fast
    ⾼高速化

    View Slide

  69. @miciek
    @miciek
    Warning
    Do not perform any of the following stunts
    on PRODUCTION.
    注意! プロダクションで⾏行行ってはいけません

    View Slide

  70. @miciek
    wrk -t1 -c16 -d30s --latency URL
    We will use wrk
    1 thread
    16
    connections
    30 sec
    duration
    ベンチマークツール: wrk

    View Slide

  71. @miciek
    We will use async-profiler
    jps
    cd async-profiler
    ./profiler.sh -d 10 -f
    https://github.com/jvm-profiling-tools/async-profiler
    プロファイラ: async-profiler

    View Slide

  72. @miciek
    We will use flame graphs
    http://www.brendangregg.com/flamegraphs.html
    read
    from
    bottom

    View Slide

  73. @miciek
    Version 1
    # requests
    99%
    latency
    avg
    latency
    req/s
    Version 1 ? ?ms ?ms ?
    -akka-http (client + server)
    -log all things
    -in mem linked list state

    View Slide

  74. @miciek
    Version 1 Results
    # requests
    99%
    latency
    avg
    latency
    req/s
    Version 1 8510 82.41ms 56.47ms 283.12

    View Slide

  75. @miciek
    Version 1 Flame Graph

    View Slide

  76. @miciek
    -don’t change the logic
    -just change the Logger interpreter
    -dropping logs if the rate is > 1k per second
    Version 2: Dropping logs

    View Slide

  77. @miciek
    Version 2 Results
    # requests
    99%
    latency
    avg
    latency
    req/s
    Version 1 8510 82.41ms 56.47ms 283.12
    Version 2 89 757 62.53ms 6.94ms 2986.26
    DroppingLogger

    View Slide

  78. @miciek
    Version 2 Flame Graph

    View Slide

  79. @miciek
    -don’t change the logic
    -change the VideoClient type class instance
    Version 3: Change the Video Client
    クライアントを代えてみる

    View Slide

  80. @miciek
    Version 3 Results
    # requests
    99%
    latency
    avg
    latency
    req/s
    Version 1 8510 82.41ms 56.47ms 283.12
    Version 2 89 757 62.53ms 6.94ms 2986.26
    Version 3 96 564 13.05ms 5.06ms 3218.48
    DroppingLogger
    Hammock (Apache)

    View Slide

  81. @miciek
    Version 3 Flame Graph

    View Slide

  82. @miciek
    -don’t change the logic
    -cache results and call logic in separate thread
    Version 4: Statistics Caching

    View Slide

  83. @miciek
    Version 4 Results
    # requests
    99%
    latency
    avg
    latency
    req/s
    Version 1 8510 82.41ms 56.47ms 283.12
    Version 2 89 757 62.53ms 6.94ms 2986.26
    Version 3 96 564 13.05ms 5.06ms 3218.48
    Version 4 933 303 62.86ms 2.87ms 31 081.82
    DroppingLogger
    Hammock (Apache)
    Stats Caching

    View Slide

  84. @miciek
    Version 4 Flame Graph

    View Slide

  85. @miciek
    Version 4 Flame Graph

    View Slide

  86. @miciek
    -don’t change the logic
    -change the underlying server from Akka HTTP
    to Http4s
    Version 5: Change the Server
    サーバーを代えてみる

    View Slide

  87. @miciek
    Version 5 Results
    # requests
    99%
    latency
    avg
    latency
    req/s
    Version 1 8510 82.41ms 56.47ms 283.12
    Version 2 89 757 62.53ms 6.94ms 2986.26
    Version 3 96 564 13.05ms 5.06ms 3218.48
    Version 4 933 303 62.86ms 2.87ms 31 081.82
    Version 5 1 158 664 9.05ms 555.80µs 38 596.24
    DroppingLogger
    Hammock (Apache)
    Stats Caching
    Http4s Server

    View Slide

  88. @miciek
    Version 5 Flame Graph

    View Slide

  89. @miciek
    Inventions That
    Already Exist
    既にあるものを発明する

    View Slide

  90. @miciek
    Introducing…

    View Slide

  91. @miciek

    View Slide

  92. @miciek
    Introducing…
    Cheaper taxi that drives on fixed routes!
    固定ルートの格安タクシーがあったら...

    View Slide

  93. @miciek
    This is a BUS. You invented a BUS.
    Cheaper taxi that drives on fixed routes!
    それはバスです。あなたはバスを発⾒見見したのです。

    View Slide

  94. @miciek
    Introducing…
    Algebras & Interpreters

    View Slide

  95. @miciek
    Algebras & Interpreters
    This is an INTERFACE. You invented an INTERFACE.

    View Slide

  96. @miciek
    Scala FP

    View Slide

  97. @miciek
    Java

    View Slide

  98. @miciek
    Interfaces

    View Slide

  99. @miciek
    Interfaces
    difference:
    we need to choose the effect type

    View Slide

  100. @miciek
    Return type
    difference:
    we need to choose the effect type
    which is very powerful

    View Slide

  101. @miciek
    Algebras

    View Slide

  102. @miciek
    Constrained effect type

    View Slide

  103. @miciek
    Dependencies

    View Slide

  104. @miciek
    Dependencies

    View Slide

  105. @miciek
    Algebras & Interpreters
    Not an INTERFACE.
    major difference:
    we can abstract over the effect type
    and constrain ourselves
    using F instead of CompletableFuture…

    View Slide

  106. @miciek
    Conclusions
    結論

    View Slide

  107. @miciek
    -changed infrastructure details
    -…but our core logic (and tests) didn’t need to
    change!
    What have we done?
    plug & play
    quickly replacing non-core-logic modules
    インフラの詳細を変えましたが、コアロジックは変えていません!

    View Slide

  108. @miciek
    Modularity / Separation of concerns
    if we can..
    replace the server implementation
    replace the state implementation
    replace the logging implementation
    replace the video client implementation
    add caching
    without
    changing the core logic (& tests)
    PURE WIN!
    コアロジックを変えることなく実装の差し替えに成功しました

    View Slide

  109. @miciek
    PURE
    ✓Collections interpreter
    ✓HTTP Web Server
    ✓HTTP Client interpreter
    ✓Collection storage interpreter
    ✓Logging interpreter
    Side-effect’y
    ✓Calculate Stats
    ✓Collections algebra
    ✓HTTP Client algebra
    ✓Logging algebra
    ✓getStats algorithm on F
    unit-tested integration-tested
    very constrained
    just F[_]
    no constraints
    Future, IO, …

    View Slide

  110. @miciek
    Interpreters integration test
    https://www.testcontainers.org/

    View Slide

  111. @miciek
    Interpreters integration test
    interpreter
    response
    https://www.testcontainers.org/

    View Slide

  112. @miciek
    You learned…
    AST &
    UNCTIONAL
    F
    F
    modularity (the λ way!)
    plug & play
    simple real-world
    service in Scala
    モジュール性とプラグアンドプレイ

    View Slide

  113. @miciek
    Learn More
    https://github.com/miciek/influencer-stats

    View Slide

  114. @miciek
    λ
    Michał Płachta
    www.michalplachta.com
    @miciek
    AST &
    UNCTIONAL
    F
    F
    Thanks!

    View Slide