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

挑戦!ISUCON de Server-side Swift 〜タイムゾーンには気をつけろ〜

Avatar for freddi(Yuki Aki) freddi(Yuki Aki)
September 11, 2022
1.8k

挑戦!ISUCON de Server-side Swift 〜タイムゾーンには気をつけろ〜

iOSDC Japan 2022
Special Thanks: http://www.ankokukoubou.com/font/onryou.htm

Avatar for freddi(Yuki Aki)

freddi(Yuki Aki)

September 11, 2022
Tweet

More Decks by freddi(Yuki Aki)

Transcript

  1. ISUCONとは、かの有名なイスカンダル(アレクサンドロス3世)が 
 紀元前320年頃に開いた異国の椅子品評会にルーツが遡る。その際、 
 かの王がこの品評会の名前を考得ていたところ、家臣の一人が「 
 椅子だしイスコンテストでいいんじゃないんすか?w」と放ち、 
 イスカンダル王が絶賛。以降その品評会はイスコンテストと呼ば れることになる。日本には安土桃山時代にシルクロードから伝わり、

    
 楽市楽座で活発に行われるようになる。かの織田信長が打たれた本 能寺の変では、このイスコンテスト落選に腹を立てた明智光秀が 
 腹いせに矢を寺にはなったところから始まるというただのとばっ 
 ちりの説がある。その後、名前の呼び方が訛り、明治時代には 
 ついにイスコンという名前に。第二次大戦などで中止になるものの、 
 現在までに毎年コンテストが開かれて、現在に至る
  2. ス ウ ィ フ ト を 愛 し ス ウ

    ィ フ ト に 愛 さ れ た 者 チ | ム 何 も わ か 
 ら ん
  3. こんな感じに! routes.get("firstUser") { req async throws -> String in guard

    let user = try await User.query(on: req.db).first() else { throw Abort(.notFound) } user.lastAccessed = Date() try await user.update(on: req.db) return user.name }
  4. Q. あれ?でも Swift Concurrency ってその時安定してたの? A. いろいろと使うのには手間があった Swift Toolchain のインストール

    サーバーがLinuxなのでインストール方法の工夫 デバッグが効かない(LLDB) < だいたいやっといたでw
  5. // swift-tools-version:5.3 import PackageDescription let package = Package( name: "isucon11",

    platforms: [ .macOS(.v10_15) ], dependencies: [ .package(url: "https://github.com/vapor/vapor.git", .branch("async-await")), .package(url: "https://github.com/vapor/mysql-kit.git", from: "4.0.0"), .package(url: "https://github.com/Flight-School/AnyCodable", from: "0.6.0"), .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.0.0"), ], targets: [ .target( name: "App", dependencies: [ .product(name: "Vapor", package: "vapor"), .product(name: "MySQLKit", package: "mysql-kit"), .product(name: "JWTKit", package: "jwt-kit"), .product(name: "AnyCodable", package: "AnyCodable") ], swiftSettings: [ .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)), // Disable availability checking to use concurrency API on macOS for development purpose // SwiftNIO exposes concurrency API with availability for deployment environment, // but in our use case, the deployment target is Linux, and we only use macOS while development, // so it's always safe to disable the checking in this situation. .unsafeFlags(["-Xfrontend", "-disable-availability-checking"]) ] ), .target(name: "Run", dependencies: [.target(name: "App")]) ] ) Package.swift (+ k8s などの設定ファイル) 作れば開発可能!
  6. 謎のPayload 上限 public func collect(max: Int? = 1 << 14)

    -> EventLoopFuture<ByteBuffer?> { switch self.request.bodyStorage { case .stream(let stream): return stream.consume(max: max, on: self.request.eventLoop).map { buffer in self.request.bodyStorage = .collected(buffer) return buffer } case .collected(let buffer): return self.request.eventLoop.makeSucceededFuture(buffer) case .none: return self.request.eventLoop.makeSucceededFuture(nil) } } max: Int? = 1 << 14 https://github.com/vapor/vapor/blob/45bc9ab1e3c4ba309606762664fc18358b7c92e5/Sources/Vapor/Request/Request%2BBody.swift#L38
  7. 謎のPayload 上限 max: Int? = 1 << 14 1 <<

    14 = 0b100000000000000 0b100000000000000 = 16(KB)
  8. ひ ょ っ と し て そ れ は ギ

    ャ グ と し て い っ て い る の か 💧 💧
  9. @discardableResult @_disfavoredOverload public func values(_ values: Encodable...) -> Self {

    let row: [SQLExpression] = values.map(SQLBind.init) self.insert.values.append(row) return self } @discardableResult public func values(_ values: SQLExpression...) -> Self { self.insert.values.append(values) return self } SQLクエリを組み立てる関数 https://github.com/vapor/sql-kit/blob/3c5413a229bc2abc962dab17ea66d25e448ad344/Sources/SQLKit/Builders/SQLInsertBuilder.swift#L94 謎のオーバーロード
  10. @discardableResult @_disfavoredOverload public func values(_ values: Encodable...) -> Self {

    let row: [SQLExpression] = values.map(SQLBind.init) self.insert.values.append(row) return self } @discardableResult public func values(_ values: SQLExpression...) -> Self { self.insert.values.append(values) return self } SQLクエリを組み立てる関数 https://github.com/vapor/sql-kit/blob/3c5413a229bc2abc962dab17ea66d25e448ad344/Sources/SQLKit/Builders/SQLInsertBuilder.swift#L94 こっち呼んでるつもり 謎のオーバーロード
  11. SQLクエリを組み立てる関数 https://github.com/vapor/sql-kit/blob/3c5413a229bc2abc962dab17ea66d25e448ad344/Sources/SQLKit/Builders/SQLInsertBuilder.swift#L94 こっち呼ばれる ちゃんとクエリ 
 つくってくれない @discardableResult @_disfavoredOverload public func

    values(_ values: Encodable...) -> Self { let row: [SQLExpression] = values.map(SQLBind.init) self.insert.values.append(row) return self } @discardableResult public func values(_ values: SQLExpression...) -> Self { self.insert.values.append(values) return self } こっち呼んでるつもり 謎のオーバーロード
  12. SQLクエリを組み立てる関数 https://github.com/vapor/sql-kit/blob/3c5413a229bc2abc962dab17ea66d25e448ad344/Sources/SQLKit/Builders/SQLInsertBuilder.swift#L94 こっち呼ばれる ちゃんとクエリ 
 つくってくれない @discardableResult @_disfavoredOverload public func

    values(_ values: Encodable...) -> Self { let row: [SQLExpression] = values.map(SQLBind.init) self.insert.values.append(row) return self } @discardableResult public func values(_ values: SQLExpression...) -> Self { self.insert.values.append(values) return self } こっち呼んでるつもり @_disfavoredOverload 謎のオーバーロード