長生村本郷Engineers'Blog

千葉県長生村本郷育ちのエンジニアが書いているブログ

AWS EC2 t2 から t3 へ移行する為の step by step

f:id:kenzo0107:20180914130511j:plain

概要

AWS EC2 に t3 系インタスタンスが登場した為、サクッとできるかと思いきや、つまづいた箇所をまとめました。

今回対象のインスタンスは HVM で ubuntu 16.04.5 LTS を使用しました。

t2 と比べて t3 は何がいいの?

t2 から t3 へ移行する大まかな流れ

要は、ena モジュールをインストールし、EC2 ENA サポートを有効化する必要がありました。

  1. t2 インスタンス停止
  2. AMI 作成
  3. t2 インスタンス起動
  4. t2 インスタンスカーネルモジュール(ena) のインストール
  5. ena モジュールインストール確認
  6. t2 インスタンス停止
  7. インスタンスタイプを t3 へ変更 (credit: unlimited もしたい場合はここで)
  8. t3 インスタンス起動

ENA って?

Elastic Network Adapter – Amazon EC2 向けの高性能パフォーマンスネットワークインターフェイス

プロセッサのワークロードを軽くし、ネットワークパケットと生成または処理を行う vCPU 間で短く効率的なパスを作成するために構築されています。

Linux インスタンスにおける Elastic Network Adapter (ENA) を使用した拡張ネットワーキングの有効化 には以下のように記載があります。

Amazon EC2 は、Elastic Network Adapter (ENA) を介して C5, C5d, F1, G3, H1, I3, m4.16xlarge, M5, M5d, P2, P3, R4, R5, R5d, X1, X1e, and z1d インスタンスに拡張されたネットワーキング機能を提供します。

拡張ネットワーキングは、Amazon EC2 コンソールから管理することはできません。

HVM インスタンスでのみサポート

まとめると、

  • Amazon EC2 向けの高性能パフォーマンスネットワークインターフェイス
  • HVM (Hardware-assited VM:完全仮想化) 環境でサポートされている。
  • PV (ParaVirtual:準仮想化) 環境ではサポートされない。
  • ENA というカーネルモジュールを介す事で、インスタンスに拡張されたネットワーキング機能が利用できる。

pv/hvm は AWS コンソール>EC2 説明の「仮想化」の項目で確認できます。
pv の場合は、 hvm の移行を検討する必要があります。

f:id:kenzo0107:20180914130817p:plain

以下から設定に進みます。

ENA 有効化設定手順

以下前提とします。

  • AMI を取る等のバックアップが済んでいる。
  • t2.small から t3.small に移行する。

Ubuntu での拡張ネットワーキングの有効化

ubuntu:~$ sudo apt-get update && sudo apt-get upgrade -y linux-aws

他OSの対応法も先ほどの Linux インスタンスにおける Elastic Network Adapter (ENA) を使用した拡張ネットワーキングの有効化 に記載されています。

W: mdadm: /etc/mdadm/mdadm.conf defines no arrays. エラーが発生した場合

/etc/mdadm/mdadm.conf ファイルに以下一文を追記します。

ARRAY <ignore> devices=<ルートデバイス>

自分の場合は以下の一文を一番下に追記して、もう一度 コマンド実行したら通りました。

ARRAY <ignore> devices=/dev/sda1

ena カーネルモジュールに関する情報表示

modinfo ena を実行し以下のように表示されれば OK です。

ubuntu:~$ modinfo ena

filename:       /lib/modules/4.4.0-81-generic/kernel/drivers/net/ethernet/amazon/ena/ena.ko
version:        1.1.2
license:        GPL
description:    Elastic Network Adapter (ENA)
author:         Amazon.com, Inc. or its affiliates
...

EC2 ENA サポート有効化

// インスタンス停止
macOS%$ aws ec2 stop-instances --instance-ids <instance id>

// ENA サポート設定
macOS%$ aws ec2 modify-instance-attribute --instance-id <instance id> --ena-support true

// EBS 最適化 (任意)
macOS%$ aws ec2 modify-instance-attribute --instance-id <instance id> --ebs-optimized

// credit unlimited 設定 (任意)
macOS%$ aws ec2 modify-instance-credit-specification --instance-credit-specification "InstanceId=i-<instance id>,CpuCredits=unlimited"

// インスタンスタイプ変更
macOS%$ aws ec2 modify-instance-attribute --instance-id <instance id> --instance-type t3.small

// インスタンス起動
macOS%$ aws ec2 start-instances --instance-ids <instance id>

これで t3 デビューを飾ることができました♪

参照

Amazon Web Servicesではじめる新米プログラマのためのクラウド超入門 (CodeZine BOOKS)

Amazon Web Servicesではじめる新米プログラマのためのクラウド超入門 (CodeZine BOOKS)

*1:本稿執筆時 2018-09-14

S3 に5分毎に出力される AWS LB ログファイルを時間帯を指定してまとめてダウンロード

概要

AWS で LB のログを S3 に保存設定をしている場合に、 インシデントがあった時間帯のログがまとめて欲しいという時に awscli でまとめてログ取得しています。

その時の手順を備忘録としてまとめました。

事前準備

  • awscli インストール

本件の実行環境は以下になります。

macOS%$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G1036

macOS%$ aws --version
aws-cli/1.15.50 Python/3.7.0 Darwin/16.7.0 botocore/1.10.49

ログファイルダウンロード

例) 2018年9月12日 14時台の ALB ログファイルをダウンロード

// 2018年9月12日 14時台のログファイルをダウンロード
macOS%$ aws s3 --profile <profile> cp s3://<log bucket name>/<lb name>/AWSLogs/123456789012/elasticloadbalancing/ap-northeast-1/2018/09/12/ . --recursive --exclude "*" --include "*20180912T05*

// ログファイル解凍
gunzip *.gz

// log を1ファイルにまとめ
cat *.log > all.log

// HTTP コードが 50x のものを 50x.log にまとめる
awk '{if($9 ~ 50) print $13,$14,$15}' all.log > 50x.log

--profile <profile>aws configure --profile <profile> で設定した場合の設定です。
default を利用する場合は --profile <profile> の指定は不要です。

以上です。

プロセスの起動経過時間・CPU使用時間

備忘録です。

プロセスがいつ頃から起動しているものか、全然再起動してないと再起動するのもやや不安になるので
一旦確認しておこう、という気持ちから以下コマンドを使っています。

$ ps -eo pid,comm,etime,time  | grep node
  591 node            51-20:47:21 00:01:54
 2255 node            23-18:07:58 00:01:18
OPTION Explain
pid プロセス ID
comm コマンド
etime プロセス開始からの経過時間
time CPU使用時間

もちろん CPU の使用頻度等も把握できるので何かと便利♪

PS(ホスファチジルセリン) 30日分

PS(ホスファチジルセリン) 30日分

食洗機かけ終わったかわからなくなる問題を RaspberryPI + BlueButton + LINE Notify + Google Home で解決した話

f:id:kenzo0107:20180820223225j:plain

概要

食洗機かけ終わったかどうかわからなくなる問題が我が家で多発していました。

それを RaspberryPI + BluetButton + LINE Notify + Google Home で解決した話です。

何が問題?

我が家では、食洗機がある程度溜まったらかける、という風にしている為、必ずかける時間が決まっていません。

その為、時折、妻or自分が食洗機を引き出した時に、「これ洗ったやつだっけ?」と疑心暗鬼・一触即発状態となり、 駆け寄った息子にドラゴンストップしていただく事態が多発していました。

記録が取れる様な仕組み、何か見ればわかる!
という状態にさえしといてもらえたら助かる、ということでエンジニアリングで解決できないか、と考えました。

解決法

開始した時刻を LINE グループに通知して記録する様にしました。*1

その通知の仕組みをボタンを一押しで済ませられる様な、シンプルなものにできないか、と考え、
家にある Raspberry PI と組み合わせられる BlueButton で実装しようと考えました。

仕組み

f:id:kenzo0107:20180817003256p:plain

  1. 食洗機を開始したら、BlueButton を押す
  2. BlueButton を押すと Bluetooth ペアリングしている Raspberry PI にボタン押したよ情報を渡す。
  3. Raspberry PI 側で起動させておいた BlueButton が押されたか判定するスクリプトが検知
  4. 3をトリガーに LINE Notify で LINE に通知。
  5. 3をトリガーに Google Home に食洗機開始したよメッセージを喋ってもらう。*2

押す長さによって処理分けしています。

  • 長押し=食洗機開始をGoogle Home, Line へ通知
  • 短押し=食洗機開始時刻読み上げ

購入したもの

Google Home

Google Home

BlueButton は Amazon で 100 円程度でした♪ お財布に優しい!

Google Home はあくまでスピーカー代わりでボタンが押された時の確認用として使ってます。
USB スピーカーを接続するでも、Lチカで反応させる、でも確認できるものがあれば、それで良いと思います。

Raspberry PI でのセットアップ

Raspberry PI 情報

$ uname -a

Linux raspberrypi 4.9.35-v7+ #1014 SMP Fri Jun 30 14:47:43 BST 2017 armv7l GNU/Linux

事前準備

  • LINE Notify に Signup し token 生成します。
    LINE Notify

  • BlueButton を Bluetooth ペアリングしときます。

ペアリングは既にいくつも記事があります。以下記事参考になるかと思います。
Bluetoothシャットダウンボタンを作る #300円でIoTボタン

google-home-notifiler インストール

  • nodejs, npm インストール
pi$ sudo apt-get update
pi$ sudo apt-get install -y nodejs npm
pi$ sudo npm cache clean
pi$ sudo npm install npm n -g
pi$ sudo n stable
  • google-home-notifiler 設定
pi$ cd ~
pi$ git clone https://github.com/noelportugal/google-home-notifier
pi$ cd google-home-notifier/
pi$ npm install
  • example.js 編集
...
const serverPort = 8091; // default port

+ var deviceName = 'ファミリールーム'; // Google Home's device name
+ var ip = '<Google Home's IP>'; // ex. 192.168.11.5
...

Google Home's IP の確認はこちら

google-home-notifler サーバ起動スクリプト作成

  • /etc/systemd/system/googlehomenotifier.service
[Unit]
Description=google-home-notifier Server
After=syslog.target network-online.target

[Service]
Type=simple
User=root
ExecStart=/usr/bin/node example.js
Restart=on-failure
RestartSec=10
KillMode=process
WorkingDirectory=/home/pi/google-home-notifier

[Install]
WantedBy=multi-user.target

上記追加後、daemon-reload し、googlehomenotifier.service を認識させます。

pi$ sudo systemctl daemon-reload

いざ google-home-notifiler 起動

pi$ sudo systemctl start google-home-notifiler

試しに hello と言わせる♪

pi$ curl -X POST -d "text=hello" http://127.0.0.1:8091/google-home-notifier

BlueButton セットアップ

pi$ sudo gem install bluebutton

食洗機 Notify スクリプト インストール

元々 python で書きましたが、shell の方が速度が出たので shell にしています。

pi$ cd ~
pi$ git clone https://github.com/kenzo0107/dishwasher
  • dishwasher.sh の以下箇所を先に生成したものと変更してください。
readonly LINENOTIFY_TOKEN="<please change yours>"

起動スクリプト設定 & 実行

pi$ sudo cp bluebutton.service /etc/systemd/system/
pi$ sudo systemctl daemon-reload
pi$ sudo systemctl start bluebutton.service

いざ実行

f:id:kenzo0107:20180820220824p:plain

できました♪

BlueButton についてちょっとだけ注意

BlueButton のボタンのトリガーの種類は以下ですが、

  • key down ボタンを押す
  • key up 押したボタンを離す
  • long key down ボタン長押し
  • long key up 長押しボタンを離す

long key down (長押し)していると、まず最初に key down イベントが発生し、その後、 long key down のイベント発生となります。

key down イベントに渡した処理がある場合、
long key down のイベントに渡した処理のみを実行する、
というのはできないので注意が必要です。

総評

食洗機開始ボタンができたおかげで家庭から争いがなくなり
イヤイヤ期だった息子も朗らかになった様に思います。

是非イヤイヤ期の子供と食洗機問題を抱えている方のお力になれば何よりです。

以上です。

*1:curl 叩ければ、後々 Slack でも何でも、家族みんなが見る所に通知すれば良いかなと思ったので

*2:Google Home はあくまでスピーカー代りです。

子供の笑顔と笑い声を聞く為に ffmpeg + Nginx + RTMP on RaspberryPI

f:id:kenzo0107:20180815181451p:plain

概要

RaspberryPI 上で rtmp モジュール付きの nginx をビルドし
WebCamera で撮影した 動画+音声付き を HLS 配信する際の手順をまとめました。

経緯

はじめは外出中にペットのうさぎ用に mjpeg-streamer でモニターしていました。
子供が生まれると、子供が元気にしてるかな、とふとモニターするようになりました。

ですが、うさぎは鳴きませんが、子供は泣き叫びます。
mjpeg-streamer では表情こそわかりますが、我が子の声が聞こえてきません。

その為、動画+音声付きで低負荷で 動画+音声 配信ができないものかと探していた際に ffmpeg に出会いました。*1

購入したもの

LOGICOOL HDウェブカム フルHD動画対応 C615

LOGICOOL HDウェブカム フルHD動画対応 C615

Nginx

http://nginx.org/en/download.html で現時点で最新バージョンをダウンロードしました。

各種ダウンロード

以下ダウンロードしています。
nginx-http-auth-digest は Nginx で Digest 認証すべくモジュール追加しました。

  • Nginx
  • nginx-rtmp-module
  • openssl
  • nginx-http-auth-digest
  • ffmpeg
// home ディレクトリで作業するとします。
pi$ cd ~

// nginx
pi$ wget http://nginx.org/download/nginx-1.15.2.tar.gz

// nginx-rtmp-module
pi$ wget -O rtmp.zip https://github.com/arut/nginx-rtmp-module/archive/master.zip
pi$ wget -O ssl.zip https://github.com/openssl/openssl/archive/master.zip

// nginx-http-auth-digest
pi$ git clone https://github.com/samizdatco/nginx-http-auth-digest.git
pi$ cd nginx-http-auth-digest
pi$ git clone https://gist.github.com/frah/3921741
pi$ patch -u < 3921741/patch-ngx_http_auth_digest_module.diff

// ffmpeg
pi$ git clone git://source.ffmpeg.org/ffmpeg.git
pi$ wget ftp://ftp.alsa-project.org/pub/lib/alsa-lib-1.1.6.tar.bz2

解凍

pi$ tar xvzf nginx-1.15.2.tar.gz
pi$ unzip rtmp.zip
pi$ unzip ssl.zip
pi$ tar xjvf alsa-lib-1.1.6.tar.bz2

Nginx ビルド

pi$ cd nginx-1.15.2/
pi$ sudo ./configure --with-http_ssl_module --with-http_realip_module --add-module=../nginx-rtmp-module-master --with-openssl=../openssl-master --add-module=../nginx-http-auth-digest
pi$ sudo make
pi$ sudo make install

Nginx Version 確認

pi$ /usr/local/nginx/sbin/nginx -V

nginx version: nginx/1.15.2
built by gcc 4.9.2 (Raspbian 4.9.2-10+deb8u1)
built with OpenSSL 1.1.1-pre9-dev  xx XXX xxxx
TLS SNI support enabled
configure arguments: --with-http_ssl_module --with-http_realip_module --add-module=../nginx-rtmp-module-master --with-openssl=../openssl-master --add-module=../nginx-http-auth-digest

Nginx をシンボリックリンクでパスが通っている場所から参照できるようにする。

pi$ sudo ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx

pi$ which nginx

ffmpeg ビルド

pi$ sudo apt-get install libomxil-bellagio-dev

pi$ cd alsa-lib-1.1.6
pi$ ./configure --prefix=/home/pi/ffmpeg
pi$ sudo make
pi$ sudo make install

pi$ cd /home/pi/ffmpeg
pi$ sudo ./configure  --enable-gpl  --enable-nonfree --enable-mmal --enable-omx-rpi --enable-omx --extra-cflags="-I/home/pi/ffmpeg/include" --extra-ldflags="-L/home/pi/ffmpeg/lib" --extra-libs=-ldl
pi$ sudo make -j4
pi4 sudo make install

sudo apt-get install libomxil-bellagio-dev を実行していない場合に以下のエラーが出ました。

ERROR: OMX_Core.h not found

録音してみる

動画撮影デバイス一覧確認

pi$ v4l2-ctl --list-device

HD Webcam C615 (usb-3f980000.usb-1.3):
        /dev/video0

上記コマンド実行時に以下のようなエラーが出る時は、

Failed to open /dev/video0: No such file or directory

以下コマンドを試してください。

pi$ sudo pkill /dev/video0

音声入力デバイス一覧確認

自分の場合は
カード 1 は WebCam
カード 2 は マイク、
です。

pi$ arecord -l

**** ハードウェアデバイス CAPTURE のリスト ****
カード 1: C615 [HD Webcam C615], デバイス 0: USB Audio [USB Audio]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0
カード 2: Device [USB PnP Sound Device], デバイス 0: USB Audio [USB Audio]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0

いざ録音

カード 2 が入力デバイスである為、 hw:2 としました。

pi$ ffmpeg -f alsa -ac 1 -i hw:2 -f v4l2 -s 640x480 -i /dev/video0 output.mpg

生成された output.mpg ファイルを mac 上にダウンロードし再生を試してみてください。

これで再生されれば、ffmpeg が問題なく動作していることを確認できたことになります。

次は配信する為の設定です。

Nginx 設定

設定ファイル格納用ディレクトリ作成

pi$ sudo mkdir -p /usr/local/nginx/conf.d

HLS ファイル生成用ディレクトリ作成

pi$ sudo mkdir -p /var/www/html/live/hls

HLS 配信用 index.html

  • hls.min.js 取得
pi$ cd /var/www/html
pi$ wget https://cdn.jsdelivr.net/hls.js/latest/hls.min.js
  • /var/www/html/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8"/>
  <script src="./hls.min.js"></script>
</head>

<body>
  <video id="video"></video>
  <script>
    if(Hls.isSupported()) {
      var video = document.getElementById('video');
      var hls = new Hls();
      hls.loadSource('/live/hls/stream.m3u8');
      hls.attachMedia(video);
      hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
    });
   }
  </script>
</body>
</html>

Digest 認証設定

pi$ cd /var/www
pi$ sudo htdigest -c .htdigest 'digest AuthNginx' hoge
password: <enter password>

各種設定ファイル配置

  • /usr/local/nginx/conf.d/default.conf
server {
    listen 8090;
    proxy_set_header   X-Forwarded-For     $proxy_add_x_forwarded_for;
    access_log /var/log/nginx/access.log combined;
    error_log /var/log/nginx/error.log warn;

    location = /favicon.ico {
        access_log off;
        empty_gif;
        expires 30d;
    }

    location / {
        auth_digest "digest AuthNginx";
        auth_digest_user_file /var/www/.htdigest;

        root /var/www/html;
        index index.html;
        set_real_ip_from    127.0.0.1;
        real_ip_header      X-Forwarded-For;
    }
}
  • /usr/local/nginx/conf.d/rtmp
rtmp {
    server {
        listen 1935;
        chunk_size 4096;
        allow play all;
        access_log /var/log/nginx/rtmp_access.log;

        application live {
            live on;
            hls on;
            record off;
            hls_path /var/www/html/live/hls;
            hls_fragment 1s;
            hls_type live;
        }
    }
}
  • /usr/local/nginx/conf/nginx.conf
user  www-data;
worker_processes  1;

pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include           mime.types;
    default_type      application/octet-stream;
    sendfile          on;
    keepalive_timeout 65;
    include /usr/local/nginx/conf.d/*.conf;
}

include /usr/local/nginx/conf.d/rtmp;

Nginx 起動設定ファイル

  • /lib/systemd/system/nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Nginx 起動

pi$ sudo systemctl daemon-reload
pi$ sudo systemctl start nginx
pi$ sudo systemctl status nginx

この時はまだ HLS ファイルが生成されていませんので
http://<RaspberryPI IP>:8090 にアクセスしても HLS 配信されていません。

f:id:kenzo0107:20180815172215p:plain

ffmpeg を起動することで /var/www/html/live/hls/ ディレクトリ以下に stream.m3u8 が生成されます。

ffmpeg 起動

pi$ sudo ffmpeg \
-f alsa -ac 1 -thread_queue_size 8192 -i hw:2 \
-f v4l2 -thread_queue_size 8192 -input_format yuyv422 -video_size 432x240 -framerate 30 -i /dev/video0 \
-c:v h264_omx -b:v 768k -bufsize 768k -vsync 1 -g 16  \
-c:a aac -b:a 128k -ar 44100 \
-af "volume=30dB" \
-f flv rtmp://localhost/live/stream;

アクセスしてみる

http://<RaspberryPI IP>:8090 にアクセスしてみます。 Digest 認証を問われるので設定した ID/PW を入力します。

f:id:kenzo0107:20180815172119p:plain

HLS 配信されていることを確認できました!

f:id:kenzo0107:20180815173337p:plain

負荷状況としては CPU 25 - 30% 程度に収まっています。

まとめ

ffmpeg + Nginx + RTMP で HLS 配信を RaspberryPI 上に構築できました。

実際の運用では、常時起動してはおらず、見たいときだけ起動するような仕組みにしており、負荷は極力抑えています。 監視は Mackerel の無料プランで今のところ十分です。

育児ハックの一環として参考になれば何よりです。

*1:勿論のことですが、家族の了承を得た上で設定しています。

Flask+Service Worker on Heroku で PWA チュートリアル

f:id:kenzo0107:20180814131355p:plain

概要

自分にとっては dev.to でバズった Service Worker。 その概要と機能性をなぞってみようとチュートリアル的に学んだ内容をまとめました。

掲題の通り、Flask + Service Worker を Heroku で動作させ、PWA(Progressive Web Apps) してみました。

lit-wildwood-62785.herokuapp.com

経緯

以前、Python の軽量 FW、Flask で Web アプリケーションを作りました。

これまでは Docker コンテナをデプロイ出来るプラットフォームを試す為に以下試してました。

上記プラットフォームでは、月数百円程度ですが、費用が発生します。

2018年8月7日、Heroku の free プランが 月 1500 時間無料とあったので アプリ×2 つ動かしても無料でいける!ということで Heroku にしてみました。

sleep 対策として以下を参照しました。 casualdevelopers.com

さらなる sleep 対策として Service Worker があればオフラインでもサービス動作させられるし、sleep し続けてもいいのでは?と思い、導入してみました。

Flask に Service Worker 導入

ソースは git にあります。

github.com

簡単に導入時のポイント

  • app.py というメインスクリプト/sw.js へのアクセスできるようにします。
@app.route('/sw.js', methods=['GET'])
def sw():
    return app.send_static_file('sw.js')

基本、上記 2 step をしてから Service Worker の各処理を実装していきます。

Install

以下の install イベントでは、指定したキャッシュさせたいファイルパスを全てキャッシュさせています。 挙動のイメージとしては、トップページにアクセスした際に Service Worker がブラウザに導入(install)されるイベントの発生時にキャッシュを生成しています。

var urlsToCache = [
  '/',
  '/static/img/favicon.ico',
  '/static/img/logo.png',
  '/static/css/bootstrap.min.css',
  '/static/css/flickity.org.css',
  '/static/js/async_set_circuit.js',
  '/static/js/bootstrap.min.js',
  '/static/js/flickity.pkgd.min.js',
  '/static/js/jquery-3.1.0.min.js',
  '/static/js/jquery.countdown.min.js',
  '/static/js/superagent.js',
  '/static/js/tether.min.js'
]

self.addEventListener('install', event => {
  console.log('install')
  event.waitUntil(
    caches.open(cacheName)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache)
      })
  )
})

Chrome > Developer Tool > Application > Cache Storage を見るとキャッシュされているのがわかります。

f:id:kenzo0107:20180814123700p:plain

fetch

以下処理は、fetch イベントでブラウザでキャッシュしたファイルを呼び出しています。

self.addEventListener('fetch', function(event) {
  console.log('fetch')
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        if (response) {
          return response;
        }
        return fetch(event.request)
      }
    )
  );
});

activate

Service Worker は active 状態になってもすぐにブラウザ上のリソースを操作できず、 もう一度ページにアクセスした際にできるようになっています。

その為、一度しかアクセスしないユーザにとっては Service Worker によるパフォーマンスの向上を体験できないことになります。

その為、 以下 activate イベントによって直ちに操作できるようにします。

self.addEventListener('activate', event => {
  console.log('activate')
  event.waitUntil(self.clients.claim());
})

基本、以上の設定で Service Worker 導入完了でした。

前後を比較すると Waterfall で見る、リソースのロードタイムがキュッと縮んでいるのがわかります。

Before f:id:kenzo0107:20180814124810p:plain

After f:id:kenzo0107:20180814124826p:plain

まとめ

Service Worker で一度キャッシュさせた後はオフラインでも動作するような仕組みが作れました。 オフラインでも動作する、というのは魅力的♪

ただし、クエリパラメータのパターンの多い URL がある場合などは キャッシュされにくく、この場合のキャッシュ戦略としては、ひとまず静的ファイルのみキャッシュするなどで対応するのが良いのか、 等考えさせられるところがありました。

例)

/ts?circuit_id=1&station_id=1 はアクセスしたけど  
/ts?circuit_id=1&station_id=2 はアクセスしてない  
という場合はオフラインにしたら /ts?circuit_id=1&station_id=2 は閲覧できなくなる

また、POST method は Service Worker は未対応で issue が上がっているようです。 Workaround として以下提案がされているブログがありましたが、実装が複雑で、まだこの辺りは開発の余地がある印象です。

medium.com

以下 Service Worker 導入時の苦労した点があり、涙無くして見られない内容でした。 日経電子版 サイト高速化とPWA対応

他趣味アプリで Workbox を利用していますが、 こちらも書いていきたいと思います。

参考

stackoverflow.com app.codegrid.net

超速! Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)

超速! Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)

Datadog NTP 監視でアラート鳴りまくり対応

f:id:kenzo0107:20180730133759j:plain

概要

サーバ時刻の監視を Datadog で実施する際、標準時刻の参照先が異なることで 不要なアラートが発生する事象がありました。

Datadog はデフォルトで pool.ntp.org を参照しています。

AWS EC2 に設定した Chrony ではデフォルトで ntp.nict.jp を参照する様にしていた為、ある日突然アラートがなりまくる事象がありました。

この対策として、 Datadog と Chrony の参照先を統一して管理する様に設定しました。

タイムサーバホストを統一する

今回は、AWS を利用しており、 AWS にも NTP サーバがある為、そちらを参照することとしました。

AWS Time Sync Service のホストは 169.254.169.123 です。

169.254.169.123 のリンクローカル IP アドレスを介してアクセス可能な為、プライベートサブネットからでもアクセス可能です。 ip アドレスという辺りがある日変更されたとかあると辛いので怖いですが、今の所、そういうことはないです。

init_config:

instances:
  - offset_threshold: 60
    host: 169.254.169.123 # 追加
# server ntp.nict.jp minpoll 4 maxpoll 4  # コメントアウト
server 169.254.169.123 prefer iburst # 追加

上記設定後、リスタート

$ sudo systemctl restart chrony
$ sudo systemctl restart datadog-agent

上記によりアラート解消されました。

参照