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

Server Side Swift実用性評価 2017 #iosdc #b

ainame
September 17, 2017

Server Side Swift実用性評価 2017 #iosdc #b

ainame

September 17, 2017
Tweet

More Decks by ainame

Other Decks in Programming

Transcript

  1. Server Side
    Swift
    実用性評価
    2017
    @ainame
    iOSDC 2017/09/17

    View full-size slide

  2. 自己紹介
    ● @ainame / Satoshi Namai
    ● iOSエンジニア
    ● RubyKaigiでもLTしてきます - 9/19

    View full-size slide

  3. 話すこと/話さないこと
    話す
    ● Server Side Swift(SSS)実際にやってみた事例 / 良い点・苦労する点
    ● Redis
    ● 今後SSS環境への希望
    話さない
    ● Web開発、vapor / Kitsura / Perfect などのFrameworkの詳細
    ● swift-server/http プロジェクト

    View full-size slide

  4. Swift OSS化
    ● 2015年末〜Swift + 各種ライブラリがOSS化
    ○ apple/swift - 本体
    ○ apple/swift-package-manager - パッケージ管理
    ○ apple/swift-corelibs-foundation - 非Apple環境でも動くFoundation
    ○ apple/swift-corelibs-libdispatch - Concurrency用Framework a.k.a GCD
    ○ apple/swift-corelibs-xctest - ユニットテスト用Framework
    ○ apple/swift-llvm, swift-clang, swift-lldb - Compiler & Debugger

    View full-size slide

  5. Swift
    Foundation
    App
    Standard Library
    Core Foundation
    Darwin
    or
    Glibc
    Dispatch
    C
    Library

    View full-size slide

  6. Swift
    Foundation
    App
    Standard Library
    Core Foundation
    Darwin
    or
    Glibc
    Dispatch
    C
    Library
    システムコール
    などOSに依存するレ
    イヤー

    View full-size slide

  7. Server Side Swiftとは?
    (とても)頑張ればなんでも書けるはず
    ● アプリケーション(Web API, Web Page, Job Queue, gRPC, …)
    ● ミドルウェア(Web Server, KVS, DB, 各種Agent, ...)
    ● 各種スクリプト(Cron, 書き捨て, ...)
    Linux上で動いたらだいたいServer Side Swiftでは??
    (現状Ubuntu上でapt install swift出来ない...)

    View full-size slide

  8. ジョブキューシステム
    を作ってみた

    View full-size slide

  9. Redis
    Web/Rails app
    Cron/Rails runner
    One-off scripts
    Worker
    Worker
    Worker
    Worker
    Ruby on Rails
    ● DB処理
    ● メール・Push通知送信
    ● Webクローラー
    ● 動画エンコーダー
    など...
    Sidekiq http://sidekiq.org/about

    View full-size slide

  10. mperham/sidekiq
    ● Rubyでもっともレイテンシーが低いジョブキューシステム
    ○ 大量のJobをLatencyが低く実行できる
    ○ スレッドベースで並列化されていて省メモリ
    IOバウンドな処理を大量にさばくのに向いている
    ○ リトライ、スケジューリング、一括再試行など自由自在
    ○ 信頼性が高い/便利機能をもつPro/Enterprise版がある
    ○ スケールアウトしても Redisにかかる負荷を低くなるような設計
    Sidekiq http://sidekiq.org/about

    View full-size slide

  11. class VideoEncodeWorker
    include Sidekiq::Worker
    def perform(video_id, size)
    video = Video.find(video_id)
    encoded_file = VideoEncoder.new.encode(video, size)
    FileUploader.new.upload(encoded_file, to: key)
    end
    end
    class VideosController < ApplicationController
    def create
    @video = Video.create!(video_params)
    ["1920x1080", "1270x720", "960x540"].each do |size|
    VideoEncodeWorker.perform_async(@video.id, size)
    end
    { status: "OK" }
    end
    end

    View full-size slide

  12. ainame/Lumpik
    ● gemのクローン
    ○ RubyのSidekiq ClientでPushするpayloadと互換があるのでJobだけSwiftも可
    ○ 使用するRedisコマンド、リトライロジックレベルで互換あるので遅いはずがない
    ● Ruby実装との違い
    ○ GCD経由でネイティブスレッドを活用し CPUバウンドな処理を並列化出来る!!
    ○ そもそもベースラインの実行速度が早いはず

    View full-size slide

  13. Redis
    Web/Rails app
    Cron/Rails runner
    One-off scripts
    Worker
    Worker
    Worker
    Worker
    Swift環境
    ● DB処理
    ● メール・Push通知送信
    ● Webクローラー
    ● 動画エンコーダー
    など...
    Sidekiq http://sidekiq.org/about
    Lumpik
    Vapor/Kituraなどが既にある
    参入者いない〜!

    View full-size slide

  14. import Foundation
    import Lumpik
    class EchoWorker: Worker {
    struct Args: Argument {
    var message: String
    }
    var jid: Jid?
    var queue: Queue?
    var retry: Int?
    required init() {}
    func perform(_ args: Args) throws {
    print(args.message)
    sleep(3)
    }
    }

    View full-size slide

  15. ベンチマーク (jobs/sec)
    x2 faster than Ruby!

    View full-size slide

  16. ListWorker
    SaveWorker
    keyword:“Swift”
    maxPage:50

    View full-size slide

  17. ListWorker
    SaveWorker
    keyword:“Swift”
    maxPage:50

    View full-size slide

  18. ListWorker
    SaveWorker
    https://aa.jp/1
    https://bb.jp/1
    https://cc.jp/3
    https://dd.jp/4
    https://ee.jp/5

    View full-size slide

  19. ListWorker
    SaveWorker

    View full-size slide

  20. Demo
    https://github.com/ainame/LumpikExample

    View full-size slide

  21. 移植方法
    ● OSS版Swift/Swift Package Manager + Xcode上で書いた
    ○ swift package generate-xcodeproj
    ● Ruby版の実装を元に可能な限り同じロジックで実装
    ○ Rubyと同じものがほぼ実装できる
    ● VaporのRedisクライアントなどを利用
    ○ SwiftのRedisクライアントの中で一番使いやすい
    ● 各種言語の標準ライブラリから実装方法を学ぶ
    ○ RubyのProcess.daemonを元に他にも ainame/Swift-Daemon を作った

    View full-size slide

  22. 良かった
    ● Xcode(IDE)が使える
    ● Swift Package Manager(v4)は普通に使える
    ● 型安全の安心感
    ● 実行速度早い

    View full-size slide

  23. 悪かった
    ● 定番のライブラリが整っていない
    ○ Foundation がカバーしてないコアな部分にオレオレ実装多い
    ○ Socket通信とか
    ○ 依存が増えてダルい
    ● CompletionHandler問題
    ○ 既存のURLSessionとかもしくはIO処理するコードには
    completionHandlerを取るものが多い
    ○ 他のサーバーサイド言語のようには書きづらい
    ...
    ● 思ったより早くない(なかった)
    ○ ボトルネックがなんなのかは正確に知る必要がある

    View full-size slide

  24. オレオレlibc問題
    まずこれを作るところから始まる

    View full-size slide

  25. mperham/sidekiq.cr
    ● Sidekiq作者によるCrystal版の実装
    ○ Crystalは静的型付で実行速度がかなり速い Rubyがグリーンスレッドで concurrency実現
    ○ 速いけどマルチコアを使いきれない
    ● ainame/Lumpikより速い(マルチコアを使ったとしても...)
    ○ Redisクライアントがボトルネックになっていた

    View full-size slide

  26. Swift vs Crystal vs Ruby (jobs/sec)

    View full-size slide

  27. SwiftのRedisクライアント
    https://github.com/ainame/swift-redis-clients-benchmark

    View full-size slide

  28. x10 faster than Vapor!
    Swift
    https://github.com/stefanwille/redis-client-benchmarks https://github.com/ainame/swift-redis-clients-benchmark

    View full-size slide

  29. Swiftのクライアントはなぜ遅い
    ● (作為的な)ベンチマーク ≠ 現実のアプリケーション
    ○ setコマンドを1,000,000回実行した時のThroughputを測っている
    ○ このベンチマークでは Pipeliningが実装されてないだけで圧倒的に遅くなる
    ● Socket通信のレイヤーがみんな独自実装
    ○ Buffering IOが実装されてない
    ○ システムコールを呼びまくってボトルネックに

    View full-size slide

  30. Performance Tuning
    ● Pipelining (Redis特有の方法) https://redis.io/topics/pipelining
    ○ 1度のIO処理で複数のコマンドを実行する方法
    ○ Redisサーバー/クライアント間のRTT(Round Trip Time)が減る
    ○ send/recvシステムコールのuser land -> kernel landへのcontext switchが減る
    ● Buffered-IO
    ○ send/recv システムコールを減らすためメモリ上のバッファを活用

    View full-size slide

  31. Pipelining
    非Pipelining
    ● Client: INCR X
    ● Server: 1
    ● Client: INCR X
    ● Server: 2
    ● Client: INCR X
    ● Server: 3
    ● Client: INCR X
    ● Server: 4
    Pipelining
    ● Client: INCR X
    ● Client: INCR X
    ● Client: INCR X
    ● Client: INCR X
    ● Server: 1
    ● Server: 2
    ● Server: 3
    ● Server: 4
    一度ずつの
    write/readで済む

    View full-size slide

  32. 実用性評価
    (感想)

    View full-size slide

  33. 感想
    ● Cのライブラリが使えばとりあえず何でも動かすのはできる
    ○ 今の所OS毎の対応を自前で対応する努力が必要
    ● Swiftで書くモチベーションとは
    ○ IO周りのライブラリがとにかく貧弱
    ○ それ他の言語でも出来るのでは・・・?
    ○ (自分の場合はミドルウェアを作る方法を実際に作って学びたかった)
    ● 既存のフレームワーク、痒いところに手が届かない(今回の例では)
    ○ Pipelining, Transactionなどの普通っぽい実装が無い

    View full-size slide

  34. Server Side Swift
    まだまだ道のりは険しい

    View full-size slide