AWS Elasticsearch Serviceの古いインデックスをcuratorを利用して削除してみました!

はじめに

こんにちは。インフラチームの高畑です。

今回、 curator を利用して AWS Elasticsearch Service に登録されているインデックスを削除するようにしてみたのでご紹介します!

curator とは

Elastic 社が提供する Elasticsearch の運用管理ツールで、インデックスのリスト表示や削除などが手軽に行えます。

curl を使用した場合のインデックスリスト表示

[user@hostname ~]# curl -XGET https://vpc-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxap-northeast-1.es.amazonaws.com/_cat/indices?v
health status index                       uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   api-nginx-access-2018.11.10 NtPFJq7gQ06fDZ8xtqarOA   5   1      35248            0      2.9mb          2.9mb
yellow open   api-nginx-access-2018.11.08 2zAfE-neQ0-2ghTfZQkxsA   5   1      40706            0      4.1mb          4.1mb
yellow open   api-nginx-access-2018.11.07 uxd-OGsbQq-k4qoteAPaGw   5   1      40406            0      4.1mb          4.1mb
yellow open   api-nginx-error-2018.11.03  9bAwxr8lSJSe1J3UE5AUfg   5   1        521            0    222.6kb        222.6kb
yellow open   ap-nginx-access-2018.11.05  VowpBW7SStmPm94xbG044A   5   1        168            0    223.3kb        223.3kb
yellow open   api-nginx-error-2018.11.04  rgKkhzhcR06eFnerLx54aw   5   1          1            0        8kb            8kb
yellow open   ap-nginx-access-2018.10.31  2LznB-GoTBm5fjb_T4bN9w   5   1        175            0    310.4kb        310.4kb
yellow open   api-nginx-access-2018.11.09 ysINQk6vRUO8FLGOiRcmnA   5   1      38718            0      3.8mb          3.8mb
yellow open   ap-nginx-access-2018.11.09  mU3ABP35Ste0VsJU64jpHQ   5   1        214            0    412.6kb        412.6kb
yellow open   ap-nginx-error-2018.11.08   wJIVXbnpSUGlpRr4KwcmwQ   5   1          8            0     61.2kb         61.2kb
yellow open   ap-nginx-access-2018.11.08  9aE7-pCTQtWbauq_7aI7xg   5   1        230            0    378.2kb        378.2kb
yellow open   api-nginx-error-2018.11.10  ZchNOQfCS4GKZ3FKWW1cfg   5   1          6            0     35.9kb         35.9kb
yellow open   api-nginx-access-2018.11.04 7D0J_NXVT6Wkmaf83B-kQw   5   1      35703            0      3.1mb          3.1mb
yellow open   api-nginx-error-2018.10.31  gnFgi1UGQbKHqCS1-m6eRg   5   1        883            0    320.6kb        320.6kb
yellow open   ap-nginx-access-2018.11.13  5VaWNCv9SNauh_1FCWSLrw   5   1          7            0     49.7kb         49.7kb
yellow open   api-nginx-access-2018.11.03 CBYDBAniRHiY-KzKiz8eiA   5   1      36741            0      3.2mb          3.2mb
yellow open   api-nginx-access-2018.11.02 RvdI42J0TrmC-lycFNWHjg   5   1      38100            0      3.6mb          3.6mb
yellow open   api-nginx-error-2018.11.09  qHjKeVtMTyOcbePYSVF5sA   5   1        538            0    220.2kb        220.2kb
yellow open   api-nginx-error-2018.11.05  _3PJCIgMT9mlbVh9jGzJNg   5   1          2            0     14.9kb         14.9kb
yellow open   ap-nginx-access-2018.11.01  IzjvuxKxRomqQdElicP10Q   5   1        157            0    260.2kb        260.2kb
yellow open   api-nginx-error-2018.11.01  oJnvclQkQtmr-btW9WkcIA   5   1          8            0     55.7kb         55.7kb
yellow open   ap-nginx-access-2018.11.03  kjFlEFifQEKXkVmfeomniw   5   1         96            0    227.8kb        227.8kb
yellow open   ap-nginx-access-2018.11.07  q4GQX8pORZS1slQSzJlsbQ   5   1        131            0    252.5kb        252.5kb
yellow open   ap-nginx-access-2018.10.30  Et4smDEyQuSLawlLOdnkHQ   5   1        144            0    294.3kb        294.3kb
yellow open   ap-nginx-access-2018.11.11  Owe3aa4gQ7aCs5mkkIA3kw   5   1         19            0    133.4kb        133.4kb
yellow open   api-nginx-access-2018.11.12 9n4sfrfFT4yCa7Kp5IFZNg   5   1      40121            0        4mb            4mb
yellow open   api-nginx-access-2018.10.31 6YxRk1kkRuWDAGDrndXApA   5   1      40941            0        4mb            4mb
yellow open   api-nginx-access-2018.10.30 bRZ_7_YeT0SZSyC0j1i7mg   5   1      38288            0      3.6mb          3.6mb
yellow open   api-nginx-access-2018.11.11 VfaS5hVKTDyFXLdjHVSecQ   5   1      35786            0      3.1mb          3.1mb
yellow open   api-nginx-error-2018.11.06  vC_QtLPmTRugJZsR7du4_w   5   1        289            0    278.6kb        278.6kb
yellow open   ap-nginx-access-2018.11.12  c97C6639SNatlNJpsVKFeA   5   1        355            0    364.2kb        364.2kb
yellow open   ap-nginx-access-2018.11.06  tV7vbxDXR_aEXwbKhWp0Sw   5   1        183            0    298.4kb        298.4kb
yellow open   api-nginx-access-2018.11.01 4UHB-q-hSCWnTaQgoDmizQ   5   1      40240            0      3.9mb          3.9mb
yellow open   api-nginx-access-2018.11.05 2Jhq-KLEQLm3HtJNrf6j6w   5   1      38685            0      3.7mb          3.7mb
yellow open   api-nginx-error-2018.11.07  99-0rOfVS42rH1vm-9CDnw   5   1        312            0    161.4kb        161.4kb
yellow open   api-nginx-error-2018.11.02  KHLZjLKRTK-wDnCLcD7Fdw   5   1        550            0    302.8kb        302.8kb
yellow open   ap-nginx-access-2018.11.02  7iB_pIGEQlygM7OQrs2CVA   5   1        136            0    230.7kb        230.7kb
yellow open   api-nginx-error-2018.11.12  Sg7P8WneQz2H_gTzwAKxfw   5   1        277            0    145.2kb        145.2kb
yellow open   api-nginx-access-2018.11.06 zwYwZHYZQcKVY90MgI3jgA   5   1      41895            0      4.2mb          4.2mb
yellow open   api-nginx-error-2018.11.08  qhH5k3cqRb-Lu9qvPh_FNw   5   1        537            0    220.4kb        220.4kb
yellow open   api-nginx-error-2018.10.30  HhB_3KPJRZe6lJBOpz9cEQ   5   1         41            0      255kb          255kb
green  open   .kibana                     -mBnXlR2QQGCuTDFEScqng   1   0         11            1     30.3kb         30.3kb
yellow open   ap-nginx-access-2018.11.04  Zh-SgjiITye2tW1krPgT0g   5   1         96            0    264.7kb        264.7kb
yellow open   api-nginx-access-2018.11.13 Ztu6V_jsTfqAx7HVcFuRNw   5   1        709            0    209.6kb        209.6kb
yellow open   api-nginx-error-2018.11.11  W44PXSWTQ9aTdE2TtMN2LQ   5   1        266            0    122.6kb        122.6kb

curator を使用した場合のインデックスリスト表示

[user@hostname ~]# curator_cli show_indices
.kibana
ap-nginx-access-2018.10.30
ap-nginx-access-2018.10.31
ap-nginx-access-2018.11.01
ap-nginx-access-2018.11.02
ap-nginx-access-2018.11.03
ap-nginx-access-2018.11.04
ap-nginx-access-2018.11.05
ap-nginx-access-2018.11.06
ap-nginx-access-2018.11.07
ap-nginx-access-2018.11.08
ap-nginx-access-2018.11.09
ap-nginx-access-2018.11.11
ap-nginx-access-2018.11.12
ap-nginx-access-2018.11.13
ap-nginx-error-2018.11.08
api-nginx-access-2018.10.30
api-nginx-access-2018.10.31
api-nginx-access-2018.11.01
api-nginx-access-2018.11.02
api-nginx-access-2018.11.03
api-nginx-access-2018.11.04
api-nginx-access-2018.11.05
api-nginx-access-2018.11.06
api-nginx-access-2018.11.07
api-nginx-access-2018.11.08
api-nginx-access-2018.11.09
api-nginx-access-2018.11.10
api-nginx-access-2018.11.11
api-nginx-access-2018.11.12
api-nginx-access-2018.11.13
api-nginx-error-2018.10.30
api-nginx-error-2018.10.31
api-nginx-error-2018.11.01
api-nginx-error-2018.11.02
api-nginx-error-2018.11.03
api-nginx-error-2018.11.04
api-nginx-error-2018.11.05
api-nginx-error-2018.11.06
api-nginx-error-2018.11.07
api-nginx-error-2018.11.08
api-nginx-error-2018.11.09
api-nginx-error-2018.11.10
api-nginx-error-2018.11.11
api-nginx-error-2018.11.12

curator を導入するに至った背景

ウィルゲート ではログ基盤として EFK ( Elasticsearch + Fluentd + Kibana ) を構築しています。

EFK を運用するにあたり、ログを絶え間なく Elasticsearch に蓄積していくためデータ量が膨大になっていき、結果的に Kibana のレスポンスが悪くなったり最悪表示ができなくなってしまうという問題がありました。

f:id:tkhttty:20181112182226p:plain

curator を導入する以前は、 古いインデックスに対して curl -XDELETE をひたすら投げるシェルスクリプトを実行して削除を行っていたのですが、古いインデックスが綺麗に削除されなかったり、 curl プロセスが大量に生成され負荷が上昇したりと運用において大きな課題となっていました。

そこで、前述した Elasticsearch の運用管理ツールである curator を利用して古いインデックスの削除を試みてみました。

導入方法

curator のインストールおよび設定には 構成管理ツールである Ansible を利用しています。

AWS の Elasticsearch へ接続する際に IAM Role を使用するため、最初に必要なモジュールである「requests_aws4auth」をインストールしてから elasticsearch-curator をインストールします。

また、curator の設定ファイルは Jinja2 テンプレートとして作成しています。

最後に 毎日 3 時に実行するように cron を設定すれば完了です。

Ansible Playbook

---

- name: install requests_aws4auth
  pip:
    name: requests_aws4auth
    state: latest

- name: install elasticsearch-curator
  pip:
    name: elasticsearch-curator
    state: latest

- name: mkdir .curator
  file: path=/root/.curator state=directory owner=root group=root mode=0755

- name: configure curator
  template: src={{ item.src }} dest={{ item.dest }} owner=root group=root mode={{ item.mode }}
  with_items:
    - { src: 'curator.yml.j2', dest: '/root/.curator/curator.yml', mode: 644 }
    - { src: 'delete_old_index.j2', dest: '/root/.curator/delete_old_index', mode: 644 }

- name: set cron curator
  cron: name={{ item.cron_name }} minute={{ item.cron_minute }} hour={{ item.cron_hour }} day={{ item.cron_day }} month={{ item.cron_month }} weekday={{ item.cron_weekday }} job={{ item.cron_job }} user={{ item.cron_user }}
  with_items: "{{ cron_list }}"

vars

cron_list:
  - cron_name: Run curator
    cron_minute: '0'
    cron_hour: '3'
    cron_day: '*'
    cron_month: '*'
    cron_weekday: '*'
    cron_job: 'curator /root/.curator/delete_old_index'
    cron_user: root

curator.yml.j2

client:
  hosts:
    - AWS ESのエンドポイント(例: vpc-kibana-xxxxxxxxxxx.ap-northeast-1.es.amazonaws.com)
  port: 443
  url_prefix:
  use_ssl: True
  certificate:
  client_cert:
  client_key:
  ssl_no_validate: False
  http_auth:
  timeout: 30
  master_only: False
 
logging:
  loglevel: INFO
  logfile:
  logformat: default
  blacklist: ['elasticsearch', 'urllib3']

delete_old_index.j2

actions:
  1:
    action: delete_indices
    description: >-
      このアクションの説明
    options:
      ignore_empty_list: True
      timeout_override:
      continue_if_exception: False
      disable_action: False
    filters:
    - filtertype: pattern
      kind: prefix
      value: 対象インデックスの接頭語(例:web-error-log-)
      exclude:
    - filtertype: age
      source: name
      direction: older
      timestring: '%Y.%m.%d'
      unit: days
      unit_count: 何日以上経過したら消すか(例:10)
      exclude:
  2:
    action: delete_indices
    :
    : 以下、対象のインデックス分追記していく
    :

導入してみて

前述したように、これまで curator ではなくシェルスクリプトから curl を投げ続けるという方法でインデックスを削除していたため、サーバの負荷が上昇してしまったり、綺麗に古いインデックスが消せずに蓄積し続けてしまうなど課題が山積みとなっていました。

今回 curator を導入してからというもの、綺麗に古いインデックスを削除しつつ全くと言っても良いほど負荷もかからないので、素晴らしくサーバ(と心の)の平穏が保たれています。

f:id:tkhttty:20181112182259p:plain

また、 curator のインストールや設定を Ansible によりコード化しているので、同様に EFK を運用している別サービスにも手軽に適用できるようになりました。

おわりに

curator を利用することにより、 AWS Elasticsearch Service に登録されている古いインデックスを綺麗に削除でき平穏が訪れてきました!

同じような悩みをお持ちの方は curator を利用してみることをオススメします!

Firebaseを利用したプッシュ通知の実装

こんにちは。メディアチームの吉田です。 暮らしニスタのアプリにFirebase Cloud Messaging(以下、FCM)を使用したプッシュ通知を導入したので、FCMの紹介と導入の経緯を説明していきたいと思います!

FCMとは

googleが提供しているメッセージを無料で確実に配信するためのクロスプラットフォーム メッセージング ソリューションです。 FCMでは管理画面上からユーザーセグメント毎の配信や個別の端末への送信ができます。 また、アプリケーション側からFCMのAPIを叩くことで任意のタイミングでプッシュ通知を送信できるようになります。

暮らしニスタのアプリにプッシュ通知を挿入した背景

暮らしニスタのアプリには以前から、プッシュ通知を送信する仕組みは導入されていました。しかし、全端末に同じ内容の送信しかできず、個人向けの通知を送ることができませんでした。 そこで、個別のプッシュ通知を送信できる仕組みの導入を行うことになりました。 暮らしニスタにはステキやコメントといった機能があり、アプリ内の通知欄には投稿した記事にコメントやステキがつくと通知が届くようになっていました。これらの通知をアプリを使っているユーザーにはプッシュ通知でお知らせすることにしました。

導入方法

FCMにはFirebase Console上で送信する方法と、APIを利用した方法の2種類があります。 Firebase Console上から送信する方法の場合、アプリ側の実装のみで送信や、開封率の取得ができるようになります。 APIを利用した方法の場合、アプリ側とアプリケーション側の実装が必要になりますが、APIで送信ができるので任意のタイミングで送信することができるようになります。一方で、開封率などは取得できないでの独自で実装する必要が出てきます。

今回の実装は、一斉送信する際は、Firebase Console上から送信する。個別のプッシュ通知はAPIを使って実装する方針に決まりました。

アプリケーションサーバーからプッシュ通知を送信する

Webアプリケーション側からプッシュ通知を送信する際にはトークンの情報が必要なので、起動時とログイン完了時にトークンを取得するようにしました。そのトークンの情報とユーザーIDを紐付けて送信する際に使用します。

単一端末へのプッシュ通知の送信

単一端末への送信は下記のようにして送信ができます。トークンと本文を設定することで送信をおこなうことができます。暮らしニスタでは通知の配信と同じタイミングで送信をするように実装しました。

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=API_KEY
{
  "to": "送信先のトークン",
  "notification" : {
    "body": "通知本文",
  }
}

データをアプリに渡す

プッシュ通知を送信する際にデータをアプリ側に渡すことができます。 暮らしニスタの場合、プッシュ通知を開封した際に、開くページを変える必要がありました。 そこで送信の際に開くページを一緒に送信し、アプリ側で開封の際に開くページを変更する実装を行いました。 dataの中で送信した値をアプリ側で取得することができます。

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=API_KEY
{
  "to": "送信先のトークン",
  "data": {
    "openUrl": "/articles"
  },
  "notification" : {
    "body": "通知本文",
  }
}

画像付きアプリケーションを送信する

iOS10以降では通知に画像をつけることができるようになりました。 FCMでは画像付きのプッシュ通知を送信することもできるようになっています。 データの送信と同様にdataの中で画像のurlを指定します。そしてmutable_contentにtrueを入れて送信します。 アプリ側ではNotification Service Extensionを使って受信した際に画像を表示する実装をおこないます。 f:id:yoshhhy:20181107112123p:plain

f:id:yoshhhy:20181031173845j:plain

最後に

FCMを使用することで簡単にプッシュ通知を送信できるようになりました。 一斉送信はもちろん、APIを用いることで個人あてのプッシュ通知の送信も実装ができるので、プッシュ通知を導入する際にはFCMを使ってみてはいかがでしょうか。

「Hacker's GATE LT & 交流会 #2」を開催しました!!【写真あり】

こんにちは!2018年新卒エンジニアの田島です。

今回は10月25日に開催された「Hacker's GATE LT & 交流会 #2」の模様をお届けしたいと思います!

Hacker's GATE とは

ウィルゲートでは、毎月1回「Hacker's GATE」という名称で社内勉強会を行っております。

最近では社内にとどまらず、社外の方をお招きしてのイベントも開催してきました。

tech.willgate.co.jp

tech.willgate.co.jp

前回のイベントからは connpass でイベントページを開設し、幅広いフィールドのエンジニアの方々と交流しています!

willgate.connpass.com

「Hacker's GATE LT & 交流会 #2」の様子

今回のテーマは「新卒入社『約』3~5年目のホンネ」ということで、お集まりいただいた発表者のみなさまに様々な「ホンネ」を語っていただきました!

f:id:tajima-ryo:20181030094805j:plain

f:id:tajima-ryo:20181029105150j:plain

f:id:tajima-ryo:20181029185524j:plain

f:id:tajima-ryo:20181029105253j:plain

f:id:tajima-ryo:20181029104951j:plain

同じエンジニアといえど辿ってきた道は千差万別。一つの業務を経て得た知見から様々な働き方のお話まで、どの LT も様々な観点から作られたバラエティに富んだ内容で、皆さんとても興味深く聞き入っている様子でした。

f:id:tajima-ryo:20181029105325j:plain

f:id:tajima-ryo:20181031153021j:plain

f:id:tajima-ryo:20181029185028j:plain

また、交流会も終始和気藹々とした雰囲気で進行し、活発な交流の場となっていました。

LT 会に参加して下さった方も、LT をしていただいた方も、本当にありがとうございました!

最後に

今後も Hacker's GATE 運営では、社外への発信を目的として LT 会や交流会を開催していく予定です。 LT をしたいという方はもちろん、色々な方の LT を聴きたい、様々な人と交流したいという方も歓迎です!

またウィルゲートでは「Hacker's GATE もくもく会」と題して、毎週木曜日にもくもく会の開催を行なっております。 こちらも参加者募集中となっておりますので、よろしくお願いいたします!

willgate.connpass.com

皆様のご参加を、心よりお待ちしております!

画面制作(html, css)をエンジニアが行うようになってからの課題と取り組み

暮らしニスタのPMを担当しているウィルゲートの水口と申します。 暮らしニスタの開発チームでは、2016年のリニューアルリリース以降、画面のコーディングをエンジニアが行っています。今ではスムーズに開発ができていますが、最初はうまくいかなかった事もありました。今回はエンジニアが画面コーディングを担当するようになってからの問題点と、これまでどう改善してきたかについて紹介させていただきます。

リニューアルまでの制作フロー

f:id:mizuguchi-harumi:20181010194019p:plain

デザイナー(制作会社など)からHTML、CSS(scss)を受け取り、エンジニアはフレームワークへの反映のみ行っていました。

リニューアル以降の制作フロー

f:id:mizuguchi-harumi:20181010194030p:plain

デザイナーはデザインまでを担当、エンジニアがHTML、CSS(scss)をコーディングするようになりました。

エンジニアが画面制作するようになってからの問題点

画面制作スキルのバラツキ

ほとんどのエンジニアが画面コーディングを担当してなかったので、メンバーごとに画面コーディングの得意不得意がありました。はじめはフロントが得意なエンジニアに画面制作の担当を寄せていましたが、それだけでは工数が足りないこともありました。ただし不得手なメンバーが担当すると、工数がかかってしまい、全体的な開発コストが膨らんでしまっていました。

デザインの連携

一部を除いてエンジニアは高機能なデザインソフトを持っていません。デザインコーディングに必要な色、サイズ等の詳細な設定値を図る方法が確立されていなかったため、デザインの把握に時間がかかっていました。

修正・手戻りの発生

デザインの連携が上手くいかなかったこと、制作に慣れていないなどが影響して、制作後のレビューとその修正に膨大な時間がかかっていました。また、画像では伝わらない画面動作等の動的な部分について、後から指摘を受けることもあり、手戻りが沢山発生していました。

上記のような問題が半年くらい続き、デザイナーも含め、メンバー間の協力体制も揺らぎかけてきました。
もっとスムーズに開発が進められるように、デザイナー、フロントエンジニアを中心にチームで改善を行ってきました。

現在のフロー

f:id:mizuguchi-harumi:20181010195008p:plain

フローと担当者は変わっていませんが、連携方法が変わりました。

改善したポイント

デザイン連携にZeplinを導入

以前は画像での連携でしたが、Zeplin(https://app.zeplin.io)というツールを使うようにしました。 このツールの導入により、デザインコーディングの制作工数と手戻りが減少できました。 ZeplinはSketchデータから簡単に作成でき、連携に使える機能が色々あります。

①要素の設定値が表示される

コーディング時に必要なサイズや色等の設定値が表示されます。 f:id:mizuguchi-harumi:20181011201106j:plain

②スタイル属性値の自動生成

ある程度の表現は自動で出力されるので、コーディング時に細かい属性を考えなくても良くなりました。

③コメント機能

Zeplinは画面にコメントをつけることができます。 デザイン画像からは判断できない事などデザインの不明点を書いたり、制作後レビューのフィードバック連携にも利用しています。 f:id:mizuguchi-harumi:20181011201113j:plain

デザインパーツの共通化

デザインの体系化・デザインガイドライン作成

ページ毎、エリア毎にデザイン制作が行われていたため、サイト内に様々なデザインが混在していました。似たようなデザインなのに、要素が統一されていないため、バラバラにCSSをコーディングする状態になっていました。
デザイナー中心にガイドラインの整備を行い、色、文字サイズ、間隔等設定値の整理からはじまり、ボタン、見出し、リスト等のデザインについても統一されました。
今では各ページのデザインについても体系化されたデザインに沿って作成されるようになっています。

スタイルガイドの整備

フロントエンジニアを中心に、CSSの構造の見直しと、体系化したデザインをもとにスタイルガイドを整備しました。

設定値の共通化(色、文字サイズ等)
f:id:mizuguchi-harumi:20180903133317p:plain

パーツ(ボタン、アイコン、画像等)の共通化
f:id:mizuguchi-harumi:20180905165656p:plain

レイアウト(グリッドシステム等)の共通化
f:id:mizuguchi-harumi:20180903134746p:plain

リスト型のレイアウトやグリッドシステムについても共通化され、楽にレイアウトを表現できるようになりました。

デザイン共通化によって、同じようなデザインを何度も書くと言うことが減りました。また、必要なコーディング量が減ったので、画面制作が得意ではないメンバーもスムーズに画面を作ることが可能になりました。

コミュニケーションの増加

デザイナーとエンジニア間でデザインの要件や意図の連携がうまくいかず手戻りが発生したり、デザインのコーディングの難易度が高すぎて、最初の見積りより工数がかかってしまうことがありました。
デザイン制作前に要件と方向性の確認し、画面制作に取り掛かるまえから認識齟齬を減らすようにしています。また、デザインコーディングの前や途中でも、密にコミュニケーションをとり、コーディングの難易度が高すぎる場合に簡単な表現に変更できないか、デザインガイドラインから離れている箇所があれば統一できないかなどの実装上の相談を都度行うようにしています。

最近の課題

これまではデザイナーが常に社内にいることが多かったのですが、最近ではデザイナーがリモートにいる事が増えてきました。基本的にはSlackで連携していますが、文字では伝わりにくい場合は、電話やSlackの動画チャットを使うようにしています。

まとめ

今回はエンジニアがコーディングを担当するようになってからの問題とどのように改善してきたかについてご紹介しました。
改善を通して、エンジニアメンバーが画面制作をスムーズに行えるようになりました。その結果、デザイナーはデザインに専念することができ、エンジニアも画面制作以外の開発にも時間を避けるようになり、チームの全体の生産力向上につながったと感じています。

Embulkを活用してAmazon Elasticsearch Serviceへデータを同期させた話

こんにちは。インフラチームの高畑です。

今回は Elasticsearch (ES) を AWS に移行した際に導入した Embulk についてお話しします!

Embulkとは

Embulk とは、 Fluentd の開発者である古橋貞之氏によって開発された、 Fluentd のバッチ版のようなものです。 プラグインにより、インプットとアウトプットを柔軟に切り替えることが可能となっており、バルク処理に特化しています。

Fluentd と Embulk の違い
Fluentd
  • データのストリーミング転送
  • 既存の大量なデータは転送ができない

Embulk
  • 定期実行によるデータ転送
  • 分散処理により既存の大量なデータを転送できる

Embulkで利用できるプラグインは以下の通りとなっています。

プラグインの一覧はこちら

Input Plugin RDS、S3、GA、ES・・・・・
Output Plugin RDS、S3、GA、ES・・・・・
Filter Plugin カラムを削ったり、再構成したり
File Parser Plugin
File Decoder Plugin
File Formatter Plugin ファイル関係
File Encoder Plugin
Executor Plugin Hadoop上で実行させたり

導入前

これまで、サービスで利用する ES を自前で構築し、JDBC ドライバを利用して RDS から ES に対しデータを転送していました。 また、ログ基盤として EFK (ES + Fluentd + Kibana) をAWS のマネージドサービスを用いて構築を行なっていました。

サービスで利用する ES を AWS ES に統一しようと考えていたのですが、AWS ES は JDBC を利用したデータ転送が出来ないという問題があり、サービス用の自前 ES とログ基盤用 AWS ES が混在するという無駄な状態となってしまいました。

そこで、これらを解決するため、JDBC での転送をやめ Embulk を利用してデータ転送を行うことにしました。

f:id:tkhttty:20181005143003p:plain

導入後

Embulk の設定ファイルはとてもシンプルな構造となっており、 RDS からデータを取得して ES へ送るだけであれば以下のように設定するだけで動作します。

(括弧で括っているところは環境に応じて変更する必要があります)

f:id:tkhttty:20180921164109j:plain

Embulkを活用して 1 日 1 回の同期処理をさせることにより、AWS ES に RDS のデータを流せるため、自前の ES は不要になり ES の混在状態を解消することができました。

またこれにより、自前で ES を管理する必要がなくなり運用コストの低下にもつながりました。

f:id:tkhttty:20181005142043p:plain

おわりに

Embulkを活用することにより、自前で構築していたESを使う必要がなくなり運用コストの削減に繋げることができました。

同様なことで悩んでいる方がいらっしゃいましたらぜひ活用してみると良いかと思います!

アプリもくもく会を開催して感じたこと

はじめに

こんにちは。ウィルゲートで開発を行っている三島です。 私の所属するメディアチームでは「暮らしニスタ」や「Milly」などのメディアサイトの構築と運用を行っています。また、webサイトだけでなくwebViewではありますが、スマートフォンアプリの開発も行っています。

今回はメディアチームでアプリについて学ぶ時間として開催している「アプリもくもく会」について紹介していきます。

f:id:MikaE:20180906214635j:plain

もくもく会を開いた背景

アプリ開発は2016年から行っていますが、ウィルゲートではこれまでwebサイト構築を主に行ってきたため、アプリ開発についての知見がありませんでした。 これまではwebViewのアプリであったため、ネイティブアプリに比べ開発難易度が低く、なんとか調べながら開発を行っていくことができていました。

アプリができてから2年ほど経ち、アプリを使ってくださるユーザーが増えてきたため、 更に使いやすいアプリにするために、アプリをネイティブ化することが決まりました。

ネイティブアプリはこれまで作成してきたwebViewのアプリよりも難易度が高く、知らないことが多いです。そのため、これまでのようにトライアンドエラーを繰り返すことは効率が悪いと感じていました。 アプリ開発を1から調べながら学ぶことは効率が悪いため、ウィルゲートでは社外のネイティブアプリ開発に知見を持っている方にアプリの技術顧問として入っていただけることが決まり、アプリ開発についておしえていただけることになりました。 技術顧問についての詳細は下記の記事を見てください。

tech.willgate.co.jp

ネイティブ化に向けて技術顧問の方に入っていただき、アプリ開発における疑問点は解消できていますが、今後webViewからネイティブへ移行することでこれまでよりもアプリの保守工数が増加することが見込まれています。 しかし、現在チーム内でアプリの開発を行っている人が私以外にいないため、必然的に対応できる人も1人です。今後アプリを開発保守していくためにも、チームとして技術の底上げが必要だと感じていました。 チームとして技術を底上げするためにアプリについて学ぶ時間を作る必要があると感じていました。アプリについて学ぶ時間として勉強会やもくもく会などがありますが、メディアチームではもくもく会を開催することにしました。

勉強会ではなくもくもく会を開催することにした理由としては以下の2点です。

  • 勉強会の形式にもよりますが、もくもく会のほうが実際に自分でコードを書く時間が多く各自のレベルに合った勉強ができる
  • 各自で勉強をしてもいいが、勉強するためには強い意志が必要になるので集まって勉強をしたほうが続きやすい

もくもく会でやっていること

もくもく会では一般的なもくもく会と同じように時間が空いた人が集まって個人でアプリについて学ぶ場にしています。 ただ漠然とアプリについて調べたり、コード書いたりするだけでは効率が悪いので、mixiさんのiOSTrainingやAppleのswiftのチュートリアルなど基礎的なことを学ぶ事ができる資料を見ながら勉強しています。

iOSTrainingはXcodeの使い方やSwiftの書き方など基礎的なところから学ぶことができるため、初心者の方におすすめできる資料だと思っています。

GitHub - mixi-inc/iOSTraining: Training course repository for iOS app developmentgithub.com

Appleのswiftのチュートリアルは英語で書かれているため読むことに時間がかかってしまいますが、簡単なCRUDのアプリを作ることができるため、楽しく学ぶ事ができるのでおすすめです。

developer.apple.com

もくもく会の感想

良かったこと

良かったこととしては、チュートリアルを進めていくことで基礎的な力はついたと感じています。また、これまで1人で勉強をしていたため疑問の解消に時間がかかっていましたが、チームで勉強を行うことで他の人に質問をすることができ、より効率よくアプリ開発について学ぶことができています。特にこれまで1人で調べ1人で解消していたため孤独を感じていましたが、雑談しながら勉強することで楽しく勉強ができ良かったと思います。 時間を作って参加してくれたチームメンバーには感謝しか無いです。

反省点

チュートリアルをこなすことで基礎は学ぶ事ができたと思いますが、実際のプロダクトコードでは応用が求められます。もくもく会チュートリアルで学んだことを実際に使ってみることができなかったです。今後は実際に題材を決めアプリを作ってみるなど応用を学ぶ事ができるように工夫していきたいです。

まとめ

アプリもくもく会を始めて3ヶ月経ち、全体として基礎的な知識はついてきたと感じています。 今後こういった活動を続けていくことで、ウィルゲートの開発組織全体としてwebアプリだけでなくネイティブアプリを開発できるようになり、より多くの人にサービスを利用してもらえるようにしていきたいです。

Chrome DevToolsを使用してサイトのパフォーマンス改善をしてみた

こんにちは!開発室メディアユニット所属新卒1年目の小澤です。
ウィルゲートでは現在(2018年9月1日)4つのメディアを出版社と協業で運営しており、そのうちの3つを自社で開発、運用・保守しています。

暮らしニスタ|知りたい!教えたい!暮らしのアイデアがいっぱい!

Milly ミリー|妊娠・出産・子育ての“今知りたい”をすぐ解決

花時間 | 花やグリーンから始まるボタニカルライフの提案

PV数や回遊率を上げるためには良質なコンテンツを提供するのはもちろんですが、その他にできる取り組みとして、UI・UXの改善、表示速度のチューニングなどがあります。
今回は、ページの表示速度を改善する一歩目として、webブラウザGoogle Chrome」に標準で搭載されている 「Chrome DevTools」を利用して簡単にサイトスピードを計測する方法を紹介します。

Chrome DevTools(旧:DeveloperTools)とは?

Googleの開発者向けサイト、Google Developersによると、

Chrome DevTools は、Google Chrome に組み込まれたウェブ作成およびデバッグツールのセットです。 DevTools を使用してサイトの反復処理、デバッグ、プロファイリングを行います。

と書いてあります。
詳しくはこちらをご覧ください。

developers.google.com

具体的な用途としては、表示崩れの原因特定、JavaScriptデバッグ、表示速度のチューニングなどがあります。
webエンジニアなら一度は使ったことがあるのではないでしょうか。
非常に多機能で本記事では紹介しきれないので、表示速度の計測方法に絞って紹介します。

表示速度の計測

今回は自社で開発、運用・保守している暮らしニスタの速度を計測します。

現在の表示速度を計測する
  1. Google Chromeで計測したいページを表示させます。
  2. Chrome DevToolsを表示させます。
    Chrome DevToolsはコンテキストメニューかキーボードショートカットから表示できます。

ウィンドウ上部にパネル名があり、標準で9つの機能がそれぞれ強力な機能を提供します。
速度を計測するためには、「Performance」タブを選択します。

google dev toolsの画像

Performanceタブ右上の歯車マークをクリックすると計測時の設定ができます。

f:id:rikipedia-5r:20180903210821p:plain

Network

計測する際の回線速度を設定できます。デフォルトは「Online」で、速度はPCが接続しているネットワークに依存します。他にも「Fast 3G」「Slow 3G」「Offline」がプリセットとして用意されており、カスタム設定もあります。

CPU

Google Chromeに割り当てられたCPUリソースの使用量を設定できます。デフォルトは「No throttling」で、特に制限は設けません。他にも「4× slowdown」「6× slowdown」がプリセットとして用意されています。

今回の計測での設定は次のようになります。

対象ページ バイス 回線速度(上り) 回線速度(下り)
https://kurashinista.jp PC 97Mb/s 97Mb/s

回線速度を一定にし、PC版の暮らしニスタトップページを計測してみます。

計測してみる

それでは早速計測してみましょう。
Performanceタブ左上の更新マークをクリックすると計測が始まります。

f:id:rikipedia-5r:20180903211226p:plain

ページによっては計測に時間がかかるのでしばらく待ちます。

f:id:rikipedia-5r:20180903211035p:plain

計測が終わりました!

f:id:rikipedia-5r:20180903211412p:plain

計測結果の詳細を説明します。

f:id:rikipedia-5r:20180903212021p:plain

①:レスポンスからページの表示が完了するまでに何が起こっているかの概要が分かります。
縦の赤線が引いてある箇所は、ページの表示が完了した時点を表しています。
赤線が引いている箇所を左端までドラッグすると、ページの表示が完了するまでの数値が分かります。 上記画像では700msあたりからページの描画が始まり、赤線が引いてある3200msあたりで表示が完了しています。

②:①で選択した範囲で何が起こっているかの詳細が分かります。
Summaryタブでは、大きく分けて6つの数値を見ることができます。

Loading

与えられたURLからHTMLを読み込んで、そこから更にレンダリングに必要な付属するリソースを読み込んで解釈していきます。 このフェーズでは主にリソースのダウンロードとパースを行います。 リソースを一式読み込んだ後、JavaScript実行(Scripting)へ移行します。

Scripting

レンダリングエンジンが、JavaScriptのコードをJavaScriptエンジンに引き渡して実行させます。

Rendering

JavaScriptの実行が終わると、今度はレイアウトツリー構築(Rendering)に移行します。この中ではスタイルの計算(Calculate Style)とレイアウト(Layout)という2つの処理が行われます。

Painting

DOMツリーのレイアウト情報の算出が終わると、最後のレンダリング結果の描画(Painting)に移ります。このフェーズでようやくレンダリングエンジンはユーザーが見ることができる実際のピクセルを描画します。ここでは、ペイント(Paint)とラスタライズ(Rasterize)とレイヤーの合成(Composite Layers)という3つの処理が行われます。 最後のComposite Layersが終わることで、ユーザーの目にはレンダリングエンジンが描画した画面が表示されます。

Other

JSエンジンのイベントループに対するオーバーヘッドの時間です。

Idle

JSやCSSなど、リソースをダウンロードしてからレスポンスが返ってくるまでの待ち時間です。

(以下から一部抜粋)

Webフロントエンド ハイパフォーマンス チューニング

Webフロントエンド ハイパフォーマンス チューニング

計測結果
Loading(ms) Scripting(ms) Rendering (ms) Painting(ms) Other(ms) Idle(ms) 合計(ms)
976.0 1215.8 330.7 57.2 578.6 720.6 3,000.5

ページの表示が完了するまでに約3秒かかっています。 日本ラドウェア株式会社の調べによると、操作開始時間の理想的な数値は3秒だと言われています。 ぎりぎり3秒台なので及第点ですね。

webtan.impress.co.jp

ちなみに理想は表示速度が爆速で有名な阿部寛のホームページです(笑)。

f:id:rikipedia-5r:20180903214442p:plain

同じ条件で計測してみたところ、暮らしニスタの約15分の1でした。道のりはまだまだ長そうです。

ボトルネックの特定

約3秒の内訳の内、40%がScriptingに使われています。 Scriptingは、先程も述べたようにJSの構文解析を行うフェーズです。 つまり、JSの容量が大きいとそれだけ読み込みにかかる時間も増えるということです。

Scriptingに問題があるということがわかったので、次に実際にボトルネックとなっているファイルを特定します。

Summaryと同じタブの「Call Tree」タブを選択します。 次に、列「Activity」の「Scripting」を選択します。 そうすると、Scriptingの中で具体的にどのイベントにどれだけ時間がかかっているかが「Evaluate Script」で分かります。

f:id:rikipedia-5r:20180903220157p:plain

青枠で囲ったあたりが今回のScriptingの大半を締めているので、この箇所がボトルネックであると分かります。 ちなみにボトルネックのファイルをたどったところ、どうやら広告の読み込みに時間がかかっていたようです。 さらにどのファイルのどこがボトルネックであるかを調べるにはJSプロファイラを利用して特定することができますが、今回の本題とは別の話なので割愛します。

対策

広告の読み込みに時間がかかっていることがわかったので、各広告の読み込みにかかる時間を計測し、 とりわけ時間のかかっている広告は一旦取り外し、その他にはasync属性をつけることによって広告の読み込みでrenderingをブロックせず、documentの解析が終わったらscriptを読み込むようにしました。 この対策によって、広告の読み込みにかかっていた時間を大幅に短縮することができました。

最後に

今回はChrome DevTools使った簡単な速度の計測方法を紹介しました。 計測の方法は他にもたくさんあり、上記のようなやり方が正解とは限りません。 ちなみにGoogleが公式で推奨しているパフォーマンスの分析方法なども紹介されていたりします。

developers.google.com

あくまでも参考程度に考えておくと良さそうです。

おまけ:速度計測の自動化

Chrome DevToolsを使い、何回か計測した平均などを求めたい場合、出力された数値を毎回コピペするのはとても煩雑で手間がかかります。 そこでおすすめなのが、サイトスピードを自動で計測し、リッチに表示してくれるsitespeed.ioです。

f:id:rikipedia-5r:20180903223058p:plain

コマンド一発で指定したURLに対して計測を自動で行います。 計測する際にはヘッドレスブラウザを使用し、詳しい値を計測しています。 他にもユーザーエージェントの選択やBasic認証などにも対応しているので、とても便利です。

それでは良い開発ライフを!