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

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

45c0e67049c82c238143b82a1660a713?s=47 ainame
September 17, 2017

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

45c0e67049c82c238143b82a1660a713?s=128

ainame

September 17, 2017
Tweet

Transcript

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

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

    - 9/19
  3. 話すこと/話さないこと 話す • Server Side Swift(SSS)実際にやってみた事例 / 良い点・苦労する点 • Redis

    • 今後SSS環境への希望 話さない • Web開発、vapor / Kitsura / Perfect などのFrameworkの詳細 • swift-server/http プロジェクト
  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
  5. Swift Foundation App Standard Library Core Foundation Darwin or Glibc

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

    Dispatch C Library システムコール などOSに依存するレ イヤー
  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出来ない...)
  8. ジョブキューシステム を作ってみた

  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
  10. mperham/sidekiq • Rubyでもっともレイテンシーが低いジョブキューシステム ◦ 大量のJobをLatencyが低く実行できる ◦ スレッドベースで並列化されていて省メモリ IOバウンドな処理を大量にさばくのに向いている ◦ リトライ、スケジューリング、一括再試行など自由自在

    ◦ 信頼性が高い/便利機能をもつPro/Enterprise版がある ◦ スケールアウトしても Redisにかかる負荷を低くなるような設計 Sidekiq http://sidekiq.org/about
  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
  12. ainame/Lumpik • gemのクローン ◦ RubyのSidekiq ClientでPushするpayloadと互換があるのでJobだけSwiftも可 ◦ 使用するRedisコマンド、リトライロジックレベルで互換あるので遅いはずがない • Ruby実装との違い

    ◦ GCD経由でネイティブスレッドを活用し CPUバウンドな処理を並列化出来る!! ◦ そもそもベースラインの実行速度が早いはず
  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などが既にある 参入者いない〜!
  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) } }
  15. ベンチマーク (jobs/sec) x2 faster than Ruby!

  16. Demo

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

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

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

  20. ListWorker SaveWorker

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

  22. 移植方法 • OSS版Swift/Swift Package Manager + Xcode上で書いた ◦ swift package

    generate-xcodeproj • Ruby版の実装を元に可能な限り同じロジックで実装 ◦ Rubyと同じものがほぼ実装できる • VaporのRedisクライアントなどを利用 ◦ SwiftのRedisクライアントの中で一番使いやすい • 各種言語の標準ライブラリから実装方法を学ぶ ◦ RubyのProcess.daemonを元に他にも ainame/Swift-Daemon を作った
  23. 良かった • Xcode(IDE)が使える • Swift Package Manager(v4)は普通に使える • 型安全の安心感 •

    実行速度早い
  24. 悪かった • 定番のライブラリが整っていない ◦ Foundation がカバーしてないコアな部分にオレオレ実装多い ◦ Socket通信とか ◦ 依存が増えてダルい

    • CompletionHandler問題 ◦ 既存のURLSessionとかもしくはIO処理するコードには completionHandlerを取るものが多い ◦ 他のサーバーサイド言語のようには書きづらい ... • 思ったより早くない(なかった) ◦ ボトルネックがなんなのかは正確に知る必要がある
  25. オレオレlibc問題 まずこれを作るところから始まる

  26. mperham/sidekiq.cr • Sidekiq作者によるCrystal版の実装 ◦ Crystalは静的型付で実行速度がかなり速い Rubyがグリーンスレッドで concurrency実現 ◦ 速いけどマルチコアを使いきれない •

    ainame/Lumpikより速い(マルチコアを使ったとしても...) ◦ Redisクライアントがボトルネックになっていた
  27. Swift vs Crystal vs Ruby (jobs/sec)

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

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

  30. Swiftのクライアントはなぜ遅い • (作為的な)ベンチマーク ≠ 現実のアプリケーション ◦ setコマンドを1,000,000回実行した時のThroughputを測っている ◦ このベンチマークでは Pipeliningが実装されてないだけで圧倒的に遅くなる

    • Socket通信のレイヤーがみんな独自実装 ◦ Buffering IOが実装されてない ◦ システムコールを呼びまくってボトルネックに
  31. 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 システムコールを減らすためメモリ上のバッファを活用
  32. 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で済む
  33. 実用性評価 (感想)

  34. 感想 • Cのライブラリが使えばとりあえず何でも動かすのはできる ◦ 今の所OS毎の対応を自前で対応する努力が必要 • Swiftで書くモチベーションとは ◦ IO周りのライブラリがとにかく貧弱 ◦

    それ他の言語でも出来るのでは・・・? ◦ (自分の場合はミドルウェアを作る方法を実際に作って学びたかった) • 既存のフレームワーク、痒いところに手が届かない(今回の例では) ◦ Pipelining, Transactionなどの普通っぽい実装が無い
  35. Server Side Swift まだまだ道のりは険しい