コネヒト開発者ブログ

コネヒト開発者ブログ

監視の民主化に向けて「モニタリングツール多くない?」という話をしました

こんにちは、サーバーサイドやっております 金城 (@o0h_)です。
最近の癒やしは「幸せカナコの殺し屋生活」です。仕事でも趣味でも何でもいいと思いますが、「私は生きているんだな!」という気持ちを抱えて育んでいくのが大事だな、と改めて気付かされます。

sai-zen-sen.jp

Tl;DR

  1. モニタリングツール増えがち問題; システムが複雑なんだ、しゃーない
  2. 「多すぎるツール」が監視ビギナーのハードルを上げていないかな。下げたい・・・!
  3. 「なぜ複数のツールが必要なのか」の肌感を共有したい
  4. まずは「最初の1つ目」のツールを習得して、次第に使えるツールを増やしていくのが良いのではないか
続きを読む

GreenkeeperからDependabotに移行しました

f:id:dachi023:20190618154616p:plain

こんにちは、安達 (@dachi_023) です。ちょうど1年前くらいにGreenkeeperを入れた話を書いたんですが、今回はそこから更にDependabotに移行した話をします。

導入にあたって

コネヒトではこれまでGreenkeeperを使って複数のリポジトリでパッケージのバージョン管理をしていましたが、それらのすべてを廃止してDependabotに移行しました。

なぜDependabotを選んだのか

GitHub傘下になったよの記事を読んで気になったのでお試しで使いはじめたのがきっかけで、Greenkeeperを使っていた時に物足りないなーと感じていた部分がDependabotでは解消されていて、乗り換えたほうが効率いいなと思ったのでGreenkeeperを解約してすべてDependabotにしました。

Dependabotの良いところ

  • 複数言語をサポートしているため、言語ごとにツールを選定する必要がない
  • 設定ファイルは必須ではなく、GUIの設定だけでも動作する
  • GitHubのPull Requestに対してAssignee, Label, Reviewerが設定できる
  • セキュリティアップデートは即時投げてくれる

複数言語のサポート

言語ごとに良さそうなツールを探してきて権限を渡して設定ファイルを作ってリポジトリに置いておく、みたいなのはしなくて良くなりそうかなと思ってます。あのツールじゃないと出来ないことがあるんだ、とかそういうのがなければ全部Dependabotに寄せておけば管理も楽で良さそうです。

f:id:dachi023:20190610151632p:plainf:id:dachi023:20190618122219p:plain

設定ファイルは不要

設定ファイルは書けますが、設定画面が提供されているので必須ではないです。ただし、各パッケージでバージョン指定をしたい場合はGUIでは指定できないようです。

f:id:dachi023:20190610152206p:plain

Assignee, Label, Reviewer

https://github.com/pulls/assignedを見て自分がボールを持っているレビューがあるかを確認しているのでAssigneeを設定できる機能がついているのが個人的にはとても嬉しいです。

セキュリティアップデート

セキュリティパッチを含むバージョンが公開されたら随時飛んでくる、というセキュリティ意識が高まる素敵な機能です。セキュリティアップデートだけPR作ってくれる、とかも可能です。

所感

機能自体には満足していますが、週ごとや月ごとにまとめて飛んでくるようにしてるとCIのジョブキューが詰まるのでそこだけ注意が必要かもなと思いました。

リンク

CodeBuildを使ったECSへのコンテナデプロイ

こんにちは。インフラエンジニアの永井(shnagai)です。

今回は、CodeBuildでのECSデプロイについて書いてみました。 普段、TravisCIを使ってメインサービスのECSのデプロイを行っているのですが、新規開発するにあたりCodeBuildを使ったECSのデプロイを組んでみたのでその内容をまとめています。

内容はざっくり下記4項目について書いてます。

  • CodeBuildのみで行うECSへのコンテナデプロイの構成図
  • 他のCIサービスと比べた時のCodeBuildの良さ
  • CodeBuildの設定でハマった点
  • デプロイフロー

CodeBuildのみで行うECSへのコンテナデプロイの構成図

CodePipelineを使ったECSへのデプロイをする選択肢もあるのですが、これだと運用フローに大きく変更が入るので今回は、現在使っているecs-deploy を使ったECSデプロイを移植する形にしました。 全体のデプロイフローとしては下記のような形になっています

f:id:nagais:20190617171151j:plain

他のCIサービスと比べた時のCodeBuildの良さ

個人的に感じた、CodeBuildによるコンテナビルドの良さについてまとめてみました。

プロジェクトの並列度を考えなくて良い

一般的なCIサービスだと契約プランによって並列度には制限あると思います。 従量課金で何プロジェクトでも並列で動かすことが出来るのはCodeBuildならではだと思います!

Dockerイメージビルド時のローカルキャッシュが設定一つで有効化出来る

コンテナをフルビルドするするとめちゃくちゃ遅いですよね。。 もちろんCIサービスでもレイヤキャッシュをバックアップしてごにょごにょすることでキャッシュすることは出来るのですが、CodeBuildだと設定一つですごく簡単に、DockerBuild時のキャッシュ設定で出来るます。 これは、革命的かと思います。

プロジェクトのアーティファクトから下記設定をすることで、Dockerのレイヤキャッシュが有効になります。

項目
キャッシュタイプ LOCAL
ローカルキャッシュオプション LOCAL_DOCKER_LAYER_CACHE

※ただ、ローカルキャッシュというだけあって、ビルドによりキャッシュが効いたり効かなかったりまちまちだなという印象です。裏側のアーキテクチャがわからないですが、これはビルドを多数繰り返すことで複数ホストにキャッシュが出来て解決されるものなのか、また別の理由なのかは運用しながら探っていければと思っています。

参考までに、検証時に試したキャッシュ利用有無でのビルド速度の違いです。 f:id:nagais:20190617171539p:plain

DockerのBUILDKITも使える

Dockerビルド高速化における切り札とも言える、BUILDKIT もランタイムのDockerが18.06以上なのでサポートされています。 ローカルのビルドはBUILDKIT前提なのだけど、CIサービスが対応してないからデプロイにかかるビルドは遅いみたいな悩みともおさらば出来ます!

buildspec.ymlに下記を記述することで利用可能になります。

DOCKER_BUILDKIT: "1"

IAM Roleで権限をコントロール出来るので、鍵の管理が不要に

IAM Roleでプロジェクト毎に必要な権限を管理出来ます。 CIのプロジェクト毎に鍵の登録をするような運用がなくなるのがgoodだなと思います。

CloudWatchEventsのトリガにCodeBuildのイベントを指定出来るので通知も簡単に書ける

TravisCIでは、エラーハンドリングをしながらSlackを呼び出すことで通知を実装していました。

CodeBuildだと、下記のようなカスタムイベントパターンを指定することで、CodeBuildのステータスをトリガにLambdaを呼び出せます。 プロジェクトの状態検知はこちらに寄せることが出来るので、簡単に通知をすることが出来ます。

このイベントを受け取りLambdaをキックすることで、Slackに飛ばす運用をしています。

{
  "source": [
    "aws.codebuild"
  ],
  "detail-type": [
    "CodeBuild Build State Change"
  ],
  "detail": {
    "build-status": [
      "FAILED",
      "IN_PROGRESS",
      "SUCCEEDED"
    ],
    "project-name": [
      "トリガに使いたいproject-name",
    ]
  }
}

イメージ

f:id:nagais:20190617175251p:plain

CodeBuildの設定でハマった点

CodeBuildは、s3でホストしている静的コンテンツ配信サイトの自動更新には使っていたのですが、久々に触ったら下記の点が変わっていたので少しハマりしました。

ランタイムの指定方法が変わっていた

これまでだと、CodeBuildのランタイム環境は、例えばjsのビルドに使う環境だとaws/codebuild/nodejs:10.1.0 というようにプロジェクト側に指定する形だったのですが、今回プロジェクトを作る中で、 aws/codebuild/standard:2.0-1.10.0 といったような standard イメージしか選択出来ないようになっていました。

トラブルシューティングにあるくらいメジャーなエラーだったのですが、、、下記サンプルのように、buildspec.ymlの中でランタイムを指定することに気づかずハマりました。

Troubleshooting CodeBuild - AWS CodeBuild

phases:
  install:
    runtime-versions:
      docker: 18
  build:
    commands:
      - echo docker tag replace started
      - ...

プロジェクトの発火条件になるGitHubのイベント設定

CodeBuildはイベントタイプ+細かな条件を指定してプロジェクトを発火出来るのですが、下記の設定にたどりつくまで色々と試行錯誤しました。

これはCodePipelineだとブランチ指定した設定しか出来なかったのを自分の中で引きずっていたというのが大きいのですが、CodeBuildではもう少し細かい発火条件が出来るのを知るまでに少し時間がかかりました。

  • masterへのpush時にプロジェクトを発火させたい場合は下記のような設定をします。

f:id:nagais:20190617172341p:plain

  • tag push時にプロジェクトを発火させたい場合は下記のような設定をします。

f:id:nagais:20190617172401p:plain

デプロイフロー

参考までに現在のこのプロジェクトのデプロイフローは下記のようになっています。

① GithubのPRベースで開発

② masterマージ時に、code buildの[StgProject]が発火して下記要領でステージングへのデプロイを実施

  • Dockerイメージのビルド
  • ECRの該当リポジトリに対して、latest というタグでpush
  • ecs-deploy(shellで書かれたツール)により、対象サービスの更新を行う

③ ステージング環境にてデプロイした変更に問題がないことを確認

④ 本番デプロイするために現在のコードに対してtagを打つ

⑤githubのtag push時に、code buildの[prdProject]が発火して下記要領で本番へのデプロイを実施

  • ECRにあるイメージをタグ名リプレイスしてコピー
    • latestrelease, releaserelease-1gen,release-1genrelease-2gen
    • aws cliのecr batch-get-image, ecr put-image を利用
  • ecs-deploy(shellで書かれたツール)により、対象サービスの更新を行う

⑥ 本番にて動作確認のテストを行う

⑦ やばいとなった時は、 ecs-emergency-rollback.sh にて緊急ロールバック(release-1genイメージ使ったロールバック)を行う

コネヒトでは一緒に成長中のサービスを支えるために働く仲間を探しています。 少しでも興味もたれた方は、是非気軽にオフィスに遊びにきていただけるとうれしいです。

AWSやDockerを駆使してサービスの信頼性を向上させるエンジニア募集 - コネヒト株式会社のインフラエンジニア中途の求人 - Wantedly

PHPフレームワークのバージョンアップを支える技術

GWいかがでしたでしょうか?
私はひたすらに「何もしないぞ!」を徹底した結果、漫画を読んで「色々な世界を旅して」「色々な出会いと別れを繰り返して」過ごしました。

その中でも、「子供はわかってあげない」を久しぶりに読み返し、

人は教わったことなら教えられるんだよ

からの

僕は誰にも教わってないんだ。・・・だから教えるのが難しいの当たり前なんだなって思って・・・少し楽になったかな

というくだりにグッと来ました。
「教えられることがある」や「教えてくれる」というのは、それだけで尊いものだな〜というリスペクトを忘れないようにしようと思うのと同時に、自分や他人の「持てるもの・持てないものを見極めて、許したり奮ったりしてけたらな」とも思いました。
なんにせよ、他人に教えられる人はすごい!🎉

子供はわかってあげない(上) (モーニング KC)

さて、こんにちは、サーバーサイドやっております 金城 (@o0h_)です。

今回は、「PHPフレームワークのマイナーアップデートをしようとしたら少し大変だったので、工夫したこと・やったこと」のお話をします。

TL;DR

  • CIの活用 / (ユニット)テストを日頃から充実させておく
  • Migration GuideやPRに目を通して、影響範囲を予想する。対応イメージを考える
  • ツールによる自動対応が可能なモノは積極的に活用する
  • 「どっかで何かが起きた」ときのgit-bisect
  • リグレッションテストの計画と実施

https://cdn-mamari.imgix.net/item/500x0_5cd98323-e73c-4933-8afd-0036ac110002.jpg.jpg

続きを読む

AWS Glueを用いてETL環境を構築したお話(RDS for MySQL → S3)

はじめに

こんにちは。2019年3月にMLエンジニアとしてJOINした野澤(@takapy0210)です。

最近はThe Mentalistという海外ドラマにお熱です。犯罪コンサルタントとして活躍する主人公の歯に衣着せぬ物言いやテンポの良さなど、見ていて爽快ですし一つ一つの作品が短いので気軽に楽しめます。(心理学に興味があると楽しさ倍増です)

前置きが長くなりましたが、初めてコネヒト開発者ブログに登場です。テンポ良くいきたいと思いますので、どうぞよろしくお願いします!

今回は機械学習基盤アップデートの一環としてAWS Glueを用いてETLしてみた話について、苦労したポイントなどを中心にお話できればと思います。

導入背景

コネヒトではママリというコミュニティサービスを運営しており、ユーザが投稿する質問に対する検閲フィルタとして機械学習が用いられています。

詳細は弊社CTOのスライドをご覧ください。

現在、モデルの更新が継続的にできていない(≒検閲フィルタのアップデートができていない)という課題があり、機械学習基盤のアップデートを実施しています。
その一環として「RDS for MySQLからデータ抽出 → 機械学習しやすい形へ加工 → S3に保存」のように良い感じでETLしたいよね!という話になり、AWS Glueに白羽の矢が立った次第です。

結論

AWS Glueを用いることでRDSに保存されているデータを抽出・加工し、それをtsv形式でS3に保存することができました。

以下その内訳です。

  • データ件数:約700万件
  • Job実行時間:5分
  • 出力tsvデータ:約3GB

結果としてはやりたいことが実現できた訳ですが、思っていたより複雑で学習コストがかかるな〜という印象を受けました。
(初見が難しいだけで、一度設定できれば以降はスムーズにいけそう感!はありました)

次項から、Glueの説明や設定方法、MySQLからのデータ抽出方法などについて述べていきます。

AWS Glueとは

AWSが提供する完全マネージド型 ETL (抽出、変換、ロード) サービスです。
公式ドキュメントはこちら

f:id:taxa_program:20190417115301p:plain
AWS Glueのアーキテクチャ図

言葉の定義について

上図を見ても分かるようにいろんなワードが出てきます。それぞれの定義が曖昧になり兼ねないので、一度整理しておきます。

  • Data Stores
    データを永続的に保存する(している)リポジトリ。S3バケットやRDS。本記事ではRDSを示す。

  • Data Source
    Job(Script)への入力として使用されるData Stores。 本記事ではRDSを示す。

  • Data Target
    データの書き込み先のData Stores。本記事ではS3を示す。

  • Data Catalog
    AWS Glue 環境を管理するためのテーブル定義、Crawler、接続情報などを管理するサービスの総称。

  • Crawler
    Data Storesに接続しデータのスキーマを判断し、Data Catalog にメタデータテーブルを作成するサービス。

  • Job
    ETL 作業を実行するために必要なビジネスロジック。プロパティ(Scriptのファイル名や保存先、接続情報)で構成される。このJobの作成時にData SourceとData Targetを指定する。 JobはApache Spark ETL ジョブPython シェルジョブの2種類から選択することができ、スケジュール起動/イベント起動が可能。

  • Script
    Jobに含まれるETLの実行処理スクリプト。S3に保存される。

構築したアーキテクチャ

今回構築したアーキテクチャの概要図です。

冒頭でも述べましたが、今回の目的はRDSに保存されている情報をGlueを使って抽出・加工し、それを.tsv形式でS3に保存することです。

f:id:taxa_program:20190417123456p:plain
今回構築したアーキテクチャ概要図

構築手順

今回は下記手順で構築しました。

  1. サブネットの作成
  2. セキュリティグループの作成
  3. Glue接続情報のIAMロール作成
  4. Glue接続情報の作成&接続テスト
  5. CrawlerのIAMロール作成
  6. Crawlerの作成&実行
  7. S3バケットの作成
  8. JobのIAMロール作成
  9. Jobの作成&実行

Glue接続情報とはData Storesへ接続するためのプロパティ情報です。これを元にClawlerを作成していきます。 そしてこのClawlerを実行してRDSのメタ情報を取得し、取得したメタ情報を元にJobでクエリを発行する、という流れです。

ここで押さえておきたい事としては、

  • Glueを利用する際には、最低限として「接続情報」「Crawler」「Job」の3つが必要だということ
  • そしてそれぞれに対してIAMロールが必要(接続情報用、Crawler用、Job用)だということ

だと思います。

構築する際のポイント

上記手順の中でも苦労したポイントについてお話します。大別すると2点です。

  • Glueには自己参照ルールが必要だった(セキュリティグループの話)
  • RDSを用いたユースケースがなかった(Jobの話)

Glueには自己参照ルールが必要だった件

手順「4. Glue接続情報の作成&接続テスト」で接続情報を作成しようとしたときに、適切なセキュリティグループを確認できません。JDBCの接続タイプを変更し、接続の追加を再試行しますというエラーメッセージが表示されました。

f:id:taxa_program:20190417150236p:plain
接続情報作成時のエラー

上記を解消するために、セキュリティグループに関しては下記のように設定する必要があります。

  • Glue 側のセキュリティグループ
    自己参照ルールにて TCP の全ポートからのインバウンドアクセスを許可する必要がある

  • Data Stores(RDS)側のセキュリティグループ
    Glueから3306ポートにアクセスできるようにする必要がある

今回の場合は、

  1. RDSにアタッチするセキュリティグループ(SG-A)とGlueにアタッチするセキュリティグループ(SG-B)を作成する。(新規作成しなくても良い。2つのSGを分けることが重要)
  2. SG-Aのインバウドルールに「TCP、ポート:3306、ソース:SG-B」を追加する。
  3. SG-Bのインバウドルールに「TCP、ポート:0-65536、ソース:SG-B」を追加する。(こちらが自己参照ルール)

という手順で設定しました。

RDS for MySQLを用いたユースケースがなかった件

冒頭でも述べましたが、GlueのJobはApache Spark ETL ジョブPython シェルジョブの2種類から選択することができます。

今回は「学習コストが低い」「分散処理するほどの大量データではない」などの観点から、Pythonシェルジョブを用いることにしました。

知の宝庫であるインターネットを駆使してユースケースを探しましたが、RDSからデータを取得するユースケースは見当たらず・・・。
公式ドキュメントなどにRedShiftを利用した事例はいくつかありました)

AWS サポートの力も借りつつ試行錯誤した結果、MySQL用のライブラリを外部よりインポートすることで実現できたので、次項でその手順をご紹介できればと思います。

PythonShellジョブからMySQLを利用する手順

Python Shellで外部のライブラリを使用したい場合はeggファイル利用する必要があります。
下記が大まかな手順です。

  1. eggファイルを作成
  2. 作成したeggファイルをS3にアップロード
  3. eggファイルをジョブに連携

こうすることで、JobからMySQLが利用可能になります。
(eggファイルの作成は、ローカルでも任意のインスタンス上でも可能ですが、python2.7がインストールされている必要があります)

1. git cloneで下記のPyMySQLライブラリをコピー

これは任意の場所にcloneすればOKです。

$ git clone https://github.com/PyMySQL/PyMySQL 

2. 任意の場所にpackage作成用のディレクトリを作成

$ mkdir package
$ cd package

3. packageを作成(python2.7.15で実行)

$ pip install PasteScript
$ paster create -t basic_package pymysql

設定項目は、全てデフォルトで進めました。

4. ソースコードを配置

1.でgit clone したディレクトリのpymysqlディレクトリの内容を、2.で作成したpackageディレクトリ配下にすべてコピーします。

$ cp -pr <git cloneしたパス>/PyMySQL/pymysql/* <2.でpackageディレクトリを作成したパス>/package/pymysql/pymysql/

※__init__.pyについては、上書き保存します。

この時点で、ディレクトリ構成は下記のようになると思います。

f:id:taxa_program:20190417184915p:plain
ディレクトリ構成

5. eggファイルを作成

packageディレクトリの配下(setup.pyファイルが作成されているディレクトリ)で、以下コマンドを実行します。
これでeggファイルが作成されます。

$ ls
-> pymysql  pymysql.egg-info  setup.cfg  setup.py 

$ python setup.py  bdist_egg
$ ls
-> build  dist  pymysql  pymysql.egg-info  setup.cfg  setup.py 

6. distディレクトリの下に、eggファイルが出来ていることを確認

$ cd dist
$ ls
-> pymysql-0.1.dev0-py2.7.egg

下記のようなeggファイルが作成されていれば問題ありません。

f:id:taxa_program:20190417185007p:plain
ディレクトリ構成

以上でインポートするeggファイルの作成は終了です。

7. 作成したeggファイルをs3にアップロード

CLIを使わずとも、マネジメントコンソール上からアップロードしても問題ありません。

$ aws s3 cp ./pymysql-0.1.dev0-py2.7.egg <s3パス>/pymysql-0.1.dev0-py2.7.egg

8. GlueのPython Shell Jobを設定

マネジメントコンソール上でジョブの作成を行います。 Pythonライブラリパスに 7.でアップロードした.eggファイルを指定してジョブを作成します。

f:id:taxa_program:20190417185200p:plain
Job作成時にPythonライブラリパスを指定

以上でMySQLが利用できるPythonShellジョブの作成は終了です。

スクリプト

参考までに、今回作成したスクリプトを公開します。 (一部、値をマスクしています)

import boto3
import sys
import csv
import pymysql.cursors
import pandas as pd
import re
from io import StringIO, BytesIO

connection = pymysql.connect(
    host='XXXXXXXXXX.rds.amazonaws.com',
    user='user',
    db='dbname',
    password='password',
    charset='utf8mb4',
    cursorclass=pymysql.cursors.DictCursor
    )

sql = "SELECT column1, column2 FROM table WHERE 0 = 0 ORDER BY column1 desc"
df = pd.read_sql(sql=sql, con=connection)

# Delete tab char
df['column1'] = df['column1'].apply(lambda x: x.replace("\t",""))

# Replace CR char
df['column1'] = df['column1'].apply(lambda x: x.replace("\n"," "))

# Convert DF to TSV format
csv_buffer = BytesIO()
df.to_csv(csv_buffer, sep='\t', encoding="UTF8") #TSV出力

# output to S3 as CSV file
bucket = "s3-bucket"
key = "hoge/hogehoge.tsv"
s3 = boto3.resource('s3')
obj = s3.Object(bucket, key)
s3response = obj.put(Body=csv_buffer.getvalue())

最後に

テンポ良くいくつもりが盛りだくさんになってしまいました。

現段階ではGlueを用いてRDSからデータ抽出するユースケースがネット上にないと思うので、この記事が一人でも多くの方の参考になれば幸いです!

imgix導入でコンテンツダウンロード量を85%削減した話

こんにちは。インフラエンジニアの永井(@shnagai)です。

今回は、imgixという画像変換に対応したCDNを導入して、コンテンツダウンロードの削減を実現した話について書こうと思います。

imgixとは

はじめに、imgixって何と思われる方も多いかと思いますので簡単に特徴を紹介します。

  • クエリパラメータで、画像のリサイズや圧縮が出来るCDNサービス
  • S3をバックエンドに指定出来るので、画像のコピー等が不要でそのまま使える
  • バックエンドはFastlyが使われているので高速配信
  • 国内だと、日経や一休で採用実績あり
  • コストは、標準プランだとCDN Bandwidth: 8¢/GB + Master images accessed $3/1000

imgix • Real-time image processing and image CDN

導入した背景

ママリが運営しているメディアサイトや記事関連のwebviewにおいて、PCサイズの大きめ画像をどのデバイスにおいても配信していたため、コンテンツダウンロード量が大きくなりモバイル回線で見た時のユーザ体験を損ねていました。

速いは正義ということで、速度改善の第一弾としてimgixの導入を決めました。 Lighthouseのスコアでも画像系の指摘が多くスコアが伸び悩んでいたのでこれを一つのKPIとして導入作業を進めました。

  • Properly size images 20s…
  • Serve images in next-gen formats 15s…

今回の移行で行ったこと

CloudFrontから配信していたサイズの大きな画像をimgixからの配信に切り替え、コンテンツダウンロード量を削減するために、移行と同時にクエリパラメータによる画像圧縮とリサイズ、フォーマット変更を行いました。

基本的なパラメータを下記にまとめたのでご参考までに。

内容 パラメータ 備考
サイズ圧縮 q=値 or auto=compress 動的に圧縮率を変更可能, autoの場合はデフォルトで75%の圧縮率
リサイズ w=値,h=値 動的にリサイズ可能
※fitパラメータで、縦横比維持、トリミング、また顔のズーム等にも対応しています。
画像フォーマット変更 auto=format 対応ブラウザ配信時にwebp対応

気になる方は、公式ドキュメント に細かく書かれているのでこちらをご覧ください。

下記のように、パラメータを付与するだけで一枚のオリジン画像から簡単にリサイズすることが出来ます。 ほぼ劣化なしにリサイズや圧縮出来る点がimgixの強みだなと個人的には感じています。

元画像 209KB

リサイズ画像(auto=format,compress&q=90&w=400) 32KB

導入後の成果

画像の最適化だけではスコアが劇的に上がるということはないのですが、下記を見ていただくとわかる通り画像系の課題が多かった関係で、一定のスコア向上を実現できました。

特に、今回の狙いだったコンテンツダウンロードサイズの削減が実現出来たことで、モバイル回線でママリを使ってくれるユーザのユーザ体験向上に寄与できた点が一番大きかったです。

コストに関しては細かくは書けないのですが、画像圧縮の結果配信量が減ったのでその分コストカットも実現出来ました。

Lighthouseの結果

そもそものスコアが低いという話はありますが、導入結果としてわかりやすいので参考として貼っておきます。

スコアという意味では、まだまだ改善の余地があるのでフロントエンドエンジニアと協力してより速さとその先にある快適なユーザ体験を追求していきたいと思っているのでまだ途上です。

  • 記事タブのwebview
項目 CloudFront imgix 差分
モバイル トータルコンテンツダウンロードサイズ 5551KB 807KB 85%減
パフォマンススコア 63 74 +11
コンテンツの初回ペイント 1.0s 0.9s -0.1s
意味のあるコンテンツの初回ペイント 3.4s 1.0s -2.4s
速度インデックス 4.7s 4.1s -0.6s
CPUの初回アイドル 6.7s 6.0s -0.7s
インタラクティブになるまでの時間 8.1s 6.7s -1.4s
入力の推定待ち時間 460ms 190ms -270ms
  • 記事ページ
項目 CloudFront imgix 差分
モバイル トータルコンテンツダウンロードサイズ 3682KB 1739KB 50%減
パフォマンススコア 29 44 +15
コンテンツの初回ペイント 1.7S 1.4s -0.3s
意味のあるコンテンツの初回ペイント 1.7s 1.4s -0.3s
速度インデックス 10.7s 6.0s -4.7s
CPUの初回アイドル 15.3s 11.0s -4.3s
インタラクティブになるまでの時間 21.9s 13.3s -8.6s
入力の推定待ち時間 160ms 140ms -20ms

導入メリット

導入メリットとして、下記が上げられます。

  • エンドユーザには、コンテンツダウンロードサイズの削減によるユーザ体験の向上を提供
  • アプリケーション的には、よく画像アップロードトリガで走らせたりする画像リサイズ処理をCDN側にオフロード出来る
  • コスト面でも、契約にはよりますがリサイズ等による配信量軽減によるコストダウン
  • 画像のリサイズを人力で行っているようなケースの場合は、その作業もすべてクエリパラメータベースに置き換えることが出来ます

注意点

最後に、imgix導入を検討する上で注意しておいた方がよい点についてもまとめておきます。

料金体系

Imgixは、Master Image数+帯域での課金になります。 Master Imageとはオリジナルのイメージ数のことで、これが無限に増えていくようなユーザアップロード用途で使うと思わぬコスト増を招く可能性があるので事前に検証してコスト計算しておくのがおすすめです。

TLS1.2未対応ブラウザへの対応

TLS1.1以前のSSL通信はサポート外なので、Androidのwebview標準ブラウザだと画像が表示されません。セキュリティ観点から世の中的には少なくなってきていますが、動作確認時にチェックするのがベターです。

サポートや営業とのやりとりは英語が必須

日本の代理店はないので、ボリュームディスカウントの交渉やテクニカルサポートはすべて英語です。ただ、とても親切に対応してくれるのであまりネックにはなりませんでした。

最後に

既に導入していた @akasakas に色々と情報をもらいスムーズに移行を進められたので、この場を借りてお礼を言いたいと思います。ありがとうございました。

コネヒトでは変化を恐れずに良いものを取り入れながらサービスの信頼性向上をミッションに一緒に働く仲間を探しています。 少しでも興味もたれた方は、是非気軽にオフィスに遊びにきていただけるとうれしいです。

www.wantedly.com

Droidcon Boston 2019に行ってきました!

f:id:tommy_kw:20190411215936j:plain

こんにちは!

Androidエンジニアの富田です。4/8、4/9にDroidcon BostonというAndroidエンジニア向けのカンファレンスがボストンで開催されました。国内のAndroidカンファレンスのブログは比較的多いと思うのですが、一方海外に目を向けると日本語ブログが少なく、どんなカンファレンス内容か気になることはないでしょうか?今回はDroidcon Bostonに参加してきましたので、気づきやナレッジを共有します。

Droidcon Bostonって?

www.droidcon-boston.com

Droidconとは、Androidエンジニア向けのグローバルなカンファレンスで、開発者同士のつながりを深めたり、技術の知見を共有するカンファレンスです。今回参加した開催地はボストンですが、それだけではなくニューヨークやロンドンなどでも開催されている大規模なカンファレンスです。

僕はDroidconに一度も参加したことがなかったのですが、DroidKaigiの登壇者、かつDroidcon Bostonスタッフでもある@droid_singhさんから‏幸運にもDroidcon Bostonのチケットを頂きましたので、初参加させて頂きました!色んな縁があるのだなとしみじみ感じたので、日々徳を積んでいこうと心に誓いました。

カンファレンス全般

Droidcon Bostonは2017年からスタートして、今年で第3回目となります。トラックは2つあり、トータル27トークセッションと4つのワークショップがありました。DroidKaigiと比べると参加者は若干少なく規模も小さめでしたが、立ち見をすることなくどのセッションでも座って落ち着いて見ることができました。

マルチトラックイベントにおいて、気になるセッションや時間を有効活用してセッションをみたいものですよね。そんな時に役立つのがカンファレンスアプリです。全体のスケジュール確認はもちろんのこと、気になるセッションが始まる前のプッシュ通知がくるので重宝しました。キャプチャではわからないのですが、カンファレンス当日には、アプリの最下部に「JUMP TO CURRENT」というボタンが表示され、それをタップすると進行中のセッションにスクロールされるようになっていました。こちらのカンファレンスアプリのソースコードも公開されているので、気になる方はご覧ください!

f:id:tommy_kw:20190413155603g:plain

カンファレンスの楽しみといえば無料でいただけるグッズですよね。ピンバッチやシールなど頂き、さらにこんな可愛いTシャツを頂きました!

f:id:tommy_kw:20190411215854j:plain
Droidcon Boston Tシャツ

また、全体を通して全てのセッションでライブスケッチを行なっていることに気づきました。下記のセッションを見ていただくと、登壇者の横に大きなボードがあるのがわかります。セッション開始と同時に下書きなしでセッション内容を描き始めます。

f:id:tommy_kw:20190411220750j:plain
Building @ speed of thoughtのセッション

そして実際に出来上がったスケッチがこちらです!60分枠のセッションがほとんどだったのですが、限られた時間でこのクオリティって...本当すごいですよね!セッション自体を見るのはもちろんですが、ライブスケッチを見るだけでも楽しめます。

f:id:tommy_kw:20190411221230j:plain
巨大なライブスケッチ

セッション一覧

セッション内容にはJetpack、Kotlin、テスト、Firebase、Flutter、Coroutine、RxJava、ML、アーキテクチャなど様々なジャンルで構成されていました。セッション一覧スライドに関しては以下のGithubにて管理されており、今年のセッションスライドだけでなく、20172018年分のセッションスライドもキャッチアップできるようになっています。ご興味ある方はぜひご覧ください!ここからは特に気になったセッションを3つ紹介します。

github.com

Do the Loco-MotionLayout: Building animations with MotionLayout

@mikescamellさんによるMotionLayoutの紹介です。MotionLayoutがどのように機能するか基礎についてサンプルコードを基に体系的に学ぶことができます。MotionSceneとは何か、またそれを利用して状態とレイアウトから分離する方法、トランジションのトリガーとなるクリックとスワイプの利用方法、KeyAttributesを利用してアニメーションの微調整方法などまで言及されていました。

f:id:tommy_kw:20190413151129g:plain
サンプルアプリ

Destination navigation: You’re going to love the transition

github.com

@emmaxさんによるNavigationアーキテクチャコンポーネントの入門紹介です。Android開発を加速するJetpackの一つであるのNavigationの利用方法について説明になります。基本利用からSafe Args、Conditional Navigation、Deep Link、テスト方法などまで言及されていました。

Leveling Up As An Android Dev

github.com

@moyheenさんによるAndroidエンジニアのキャリアについての紹介です。Android向けの技術カンファレスなので技術的な内容のセッションは多いですが、このセッションではキャリアについて紹介されています。Androidエンジニアの各レベルで求められていることって意外とわからないものですよね。今回紹介されていた内容は以下の通りです。

  • ジュニアエンジニア
  • ミドルエンジニア
  • シニアエンジニア
  • リードエンジニア
  • マネジメント
  • その他(GDEなど)

各レベルで何をすべきか、そして今のレベルを把握することによって、次のレベルに前進するための情報を得ることができます。

最後に

ひょんなことからDroidcon Bostonに参加させてもらったのですが、グローバルなカンファレンスであり、かつ豊富なジャンルのセッションでとても刺激的でした。スライド一覧を見ていただくと興味のある内容もあると思いますのでぜひご覧ください!また、Droidconはボストンだけでなく、様々な地域で開催されているため、Droidcon Bostonをきっかけに他のDroidconにも参加して行きたいと思います。以上になります、ありがとうございました!