読者です 読者をやめる 読者になる 読者になる

テクノロジーサイドからみた○○ x Tech

ここの5〜6年の間 (特定の分野) x Techというワードをよく聞きます。 長年「ITの不毛の分野」と言われてた産業にテクノロジーが注入される事により、○○ x Techと称されます。 近年だと、Ad Tech、Fin Tech、Ed Tech、Fashion Tech、Food TechそしてHR Tech等があります。

ちなみには我々もHRテクノロジー大賞奨励賞というのを昨年受賞しています。

それぞれの分野でテクノロジーのトレンドとビジネスのトレンドがうまく合致するタイミングで、○○Techというワードがメディアにでてくる事になります。もしくは恣意的に業界全体が出すように仕向けます。 GoogleApple等の大手だけがこれらのメリットを享受するのではなく、それぞれの分野で新しいスタートアップが現れます。 スタートアップが新しいテクノロジーを生み出す事もあれば、大手企業が生み出したテクノロジーにスタートアップがうまくビジネスに取り入れるパターンがあります。 過去の○○Techというのを振り返ってみると、それぞれの時代でソフトウェア・ハードウェア問わずどういったテクノロジーの進化があったのでしょうか。

Ad Tech(広告 x テクノロジー)

  • 2009年頃〜
  • リアルタイムで入札できる仕組みの登場(RTB)
  • 複数のアドネットワークへの配信の登場(DSPSSP)
  • リーマンショック後、ニューヨークの金融関係者がこの業界に流れた(都市伝説?)

株式の自動取引のテクノロジーが広告の自動入札に流れてきたとか言われてましたが、RTBの登場後は広告枠を買う人と売る人の間に様々なプレイヤーが現れました。

Ed Tech(教育 x テクノロジー)

  • 2011年頃〜
  • タブレットの登場により、幼児教育にタブレットが使われる
  • 通信環境の改善によるICTを活用した遠隔授業、MOOCs
  • 学校の教職員のITリテラシー向上、ITに慣れ親しんでる年齢層が決裁者になってきている

タブレット登場後、幼児教育を中心とした知育アプリが乱立しました。また、映像配信に耐えうる通信環境とクラウドサーバーにより大学が社会人に向けた講座をオンラインで開講する等の動きが加速しました。

Fin Tech(金融 x テクノロジー)

上記は支払い関係を効率化するものがメインですが、保有資産の一元管理するツール(Money Tree, Money forward等)が多くでてきてこれも含めFinTechですね。現金をあまり使わないアメリカの方がこのあたりは盛んな感じがします。

HR Tech(人材 x テクノロジー)

では、今流行りのHR Tech流行の背景はなんなのかをテクノロジーサイドから読み解くと、実はそこまで多くでてきません。 HRと一言でいっても候補者獲得、スクリーニング、戦力化、タレントマネジメント、人事労務管理等があり、HR Techはスクリーニングとタレントマネジメントの部分で語られる事が多いです。 他の産業と同様にテクノロジーの動きをみてみると、大きなところで

等があります。

これだけ? と思うのですが、ビジネスサイドでないテクノロジーサイドにフォーカスすると案外少ないです。 機械学習の大衆化というのは、大量のデータを効率よく溜め込んでいくというのは、その辺のアプリケーションエンジニアやインフラエンジニアでも可能になりました。そして機械学習の部分もライブラリも豊富に揃っているのでデータサイエンティストだけの仕事ではなくなりました。(その先の意味ある分析から戦略立案は彼らの仕事ですね)

そして人工知能ブーム。人に代わって人工知能が採用して育成してくれるというのはまだ先の話で、あくまで人の思考をサポートする役割にとどまります。

人工知能がHRの領域で活躍するには、デジタル化されてない人の行動ログがもっと必要です。 人の活躍・気持ちの変化を察知するには、人の行動ログが大量に必要なのにも関わらず、まだデジタル化された情報だけに頼っています。 声の大きさ、歩く速度、会話の量など人の状態を把握するのに必要なデータは正規化されてないオフラインにある事が多いです。これをデジタル化するとHR Techというのはもっと加速するはずです。この辺りは人工知能の出番かもしれないですね。

最後に脱線しますが、社会保険の電子化はもっと加速してほしいです。 年末調整の用紙に自分で計算した金額書き込んで保険会社からのはがき添付して提出する文化がなくなるのはいつになるのでしょうか。

PHPプロファイラ XHProf と XHGui と Callgraph をインストール

こんにちは、エンジニアのあらきです。
最近、外はめっきり寒くなってきました。

うちのマンションは昭和生まれということで気密性が低いです。さらに窓や扉の高さが低いため、午前中でも奥まで光が入ってきません。
なので朝と夜はメチャ寒い。特に朝。
もうね、ほんと、布団が恋しい(´ー`)
身体が重くて布団から出られません(´ー`)

・・・

重いといえば!

色々と開発をしている中で、いつの間にかやたらと表示が重いページが出てきます。何秒とかかかります。メモリが256MBだとか、回線がISDNだとかではありません。

「いったいどこが重いねん(゚д゚)」

ってことで、Facebook製のPHPプロファイラ『XHProf』をローカル環境にインストールして、どのメソッドがノロマな亀になっているのかを探りました。

環境

  • PHP 5.6
  • nginx(今回はSSLページに設定)
  • MySQL

目標

XHProfで取得した情報を、XHGuiとCallgraphで確認できるようにして、ボトルネックを発見する

XHProfのインストール

まずはXHProfのインストールをしましょう。

$ pecl install channel://pecl.php.net/xhprof-0.9.4

次にphp.iniを編集してインストールしたXHProfを認識させます。

$ vim /etc/php.ini

# 最終行でいいので、以下を入力
[xhprof]
extension=xhprof.so

ウェブサーバーを再起動して、インストールの確認をします。

# nginxを再起動
$ /etc/init.d/nginx restart

# インストール確認
$ php --ri xhprof

xhprof => 0.9.2

XHGuiのインストール

続いてXHGuiのインストールです。

XHGuiのダウンロード

まずはXHGuiをダウンロードしましょう。
(今回は直接ファイルをダウンロードする形で進めていきます)
https://github.com/pierrejoye/xhprof-pr
f:id:i-plug-develop:20161101164421j:plain

ダウンロードしたzipを解凍。xhprof-prフォルダをドキュメントルートに設置します。

# xhprof-pr → xhprofにリネームしました
$ ~/public_html/xhprof

$ cd ~/public_html/xhprof

各種ファイルの編集

次に各種ファイルの編集を行っていきます。

# header.phpファイル
$ vim external/header.php
// コメントアウト
register_shutdown_function('xhprof_shutdown_function');
 ↓
// register_shutdown_function('xhprof_shutdown_function');

configファイルはサンプルからコピーを作成します

# サンプルからコピーを作成
cp xhprof_lib/config.sample.php xhprof_lib/config.php
// DBの情報を適宜設定
$_xhprof['dbtype'] = 'mysql'; // Only relevant for PDO
$_xhprof['dbuser'] = 'user';
$_xhprof['dbpass'] = 'password';
$_xhprof['dbname'] = 'xhprof';
$_xhprof['dbadapter'] = 'Pdo';
$_xhprof['url'] = 'https://xhprof.example.jp';
// $controlIPs = falseを有効に
// $controlIPs = false;
$controlIPs = array();
$controlIPs[] = "127.0.0.1";
$controlIPs[] = "::1";
 ↓
$controlIPs = false;
// $controlIPs = array();
// $controlIPs[] = "127.0.0.1";
// $controlIPs[] = "::1";`|

データベースの設定

次にデータベースの設定を行います。

-- MySQLにDB名『xhprof』を作成
mysql> CREATE DATABASE xhprof;

続いてテーブルを作成しますが、xhprof_lib/utils/Db/Pdo.phpの冒頭にCreate table文がコメントアウトで記載されているので、それをそのまま実行します。

$ vim xhprof_lib/utils/Db/Pdo.php
mysql> CREATE TABLE `details` (
         `id` char(17) NOT NULL,
         `url` varchar(255) default NULL,
         ...

nginxの設定

次にnginxの設定を行っていきましょう。 まずは、おおもとのnginx.confにconf.d以下のconfファイルを読み込む設定をします。

http {
    ...

    include /etc/nginx/conf.d/*.conf;
}

続いて、xhprof用のconfファイルを作成します。

$ vim /etc/nginx/conf.d/xhprof-ssl.conf
server {
    listen       443;
    server_name  xhprof.example.jp;

    ssl on;
    ssl_certificate /etc/nginx/ssl.hoge.crt;
    ssl_certificate_key /etc/nginx/ssl.hoge.key;

    set_real_ip_from   172.31.0.0/16;
    real_ip_header     X-Forwarded-For;

    root   /home/example/xhprof/xhprof_html/;
    index  index.html index.php;

    location = /robots.txt { access_log off; log_not_found off; }
    location = /favicon.ico { access_log off; log_not_found off; }

    location ~ \.(php|phar)$ {
        expires off;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

そして、解析するサイトのconfファイルにxhprofのheader.phpとfooter.phpを読み込むように設定

$ vim /etc/nginx/conf.d/example-ssl.conf
location ~ \.(php|phar)$ {
    include /etc/nginx/fastcgi_params;

    ...

    # 以下を追加
    fastcgi_param PHP_VALUE "auto_prepend_file=/var/www/example/public/xhprof/external/header.php \n auto_append_file=/var/www/example/public/xhprof/external/footer.php";
}

ここまで設定できたらnginxとphp-fpmを再起動します。

$ /etc/init.d/nginx restart
$ /etc/init.d/php-fpm restart

設定は以上です。

XHProfでの解析のON/OFFと解析データ確認

解析

XHProfでの解析を行う場合、解析したいページURLに『_profile=1』パラメータをつけてアクセスします。
https://example.jp?_profile=1
アクセスすると、以降停止するまで自動で解析し続けます。
ページ遷移をした場合は、遷移先のページが解析されます。

解析を停止するには、URLに『_profile=0』をつけてアクセスします。
https://example.jp?_profile=0

データ確認

/etc/hostに以下を追記して

# IPは適宜変更してください
192.168.33.10  xhprof.example.jp

ページにアクセスすれば、解析されたデータが確認できます。
https://xhprof.example.jp
f:id:i-plug-develop:20161101164352j:plain

Callgraphのインストール

最後にコールグラフをインストールします。

$ yum install graphviz graphviz-gd

xhprofのconfig.phpの以下のコメントアウトを外す

$ vim xhprof_lib/config.php
/*
$_xhprof['dot_binary']  = '/usr/bin/dot';
$_xhprof['dot_tempdir'] = '/tmp';
$_xhprof['dot_errfile'] = '/tmp/xh_dot.err';
*/

 ↓

$_xhprof['dot_binary']  = '/usr/bin/dot';
$_xhprof['dot_tempdir'] = '/tmp';
$_xhprof['dot_errfile'] = '/tmp/xh_dot.err';

コールグラフ確認

https://xhprof.example.jpにアクセスして、該当データのTimestampをクリック
→ View Callgraphをクリック → 以下のようなコールグラフが表示されればOKです
f:id:i-plug-develop:20161101164247j:plain

まとめ

というわけで、無事ノロマな亀を発見することができました(えらい重たいクエリが...)

こういうボトルネックとなる部分が、視覚的にパッとわかるのは(・∀・)イイネ!!
私みたいな未熟者には大変助かります。神Facebook

Serverless FrameworkでChatwork通知用APIを作成する方法

こんにちは。串上です。
前回ReactとAWS API Gatewayの連携方法を書いた者です。

前回の記事を読んでいただいた方は思ったかもしれませんが、API Gatewayって手動で設定するの面倒ですよね。

そこで今回はそのあたりの設定をコマンド一発で自動化してくれる素敵なフレームワークであるServerless Framework(v1.1)について書きたいと思います。 https://serverless.com/

Serverless Frameworkを利用するにあたって、 AWS CLIAWSコマンドラインからごにょごにょするツール)をインストールする必要があるので、まずはそちらから。

pipをインストール

curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py

え、AWS CLIちゃうん?って思った方、そうあせらないでください。
AWS CLIをインストールするためにはPythonのパッケージ管理ツールpipが必要なんです。
とりあえず入れて下さい。

こんな感じになればインストール完了です。

Collecting pip
  Downloading pip-9.0.1-py2.py3-none-any.whl (1.3MB)
    100% |████████████████████████████████| 1.3MB 816kB/s
Collecting wheel
  Downloading wheel-0.29.0-py2.py3-none-any.whl (66kB)
    100% |████████████████████████████████| 71kB 5.9MB/s

次に行きます。

AWS CLIをインストール

sudo pip install awscli

で、OKと思ったらsixがどうちゃら言われてエラーが出たら、以下の魔法版で実行して下さい。

sudo pip install awscli --upgrade --ignore-installed six

するとこんな感じにインストールが完了します。

Collecting awscli
  Downloading awscli-1.11.15-py2.py3-none-any.whl (1.0MB)
    100% |████████████████████████████████| 1.0MB 804kB/s
Collecting six
  Downloading six-1.10.0-py2.py3-none-any.whl
...
Successfully installed awscli-1.11.15 botocore-1.4.72 colorama-0.3.7 docutils-0.12 futures-3.0.5 jmespath-0.9.0 pyasn1-0.1.9 python-dateutil-2.6.0 rsa-3.4.2 s3transfer-0.1.9 six-1.10.0

AWS CLIのインストールは完了しましたが、このままではまだ「だれのAWSに接続するん?」って話なんで、そのあたりも設定していきます。

AWS CLIの設定

aws configure

ってコマンドを打つと、以下のように質問してくるので答えます。

AWS Access Key ID [None]: xxxxxxxxxx
AWS Secret Access Key [None]: yyyyyyyyyy
Default region name [None]: ap-northeast-1
Default output format [None]: json

region nameとoutput formatは好きに変えて下さい。
自分はjson好きの日本在住なので上記の設定にしています。

xxxxxxxxxxとyyyyyyyyyyはAWSのユーザーを作成したときの一回だけしかダウンロードまたは表示ができないアレです。
一回だけだなんて厳しいですよね。
しかもユーザー作成したときなんて何にもわかってないときやのに、ダウンロードってなんやねんって感じですよね。
でもダウンロードはしといてください。
そして安全な場所に保管しておいて下さい。
確かファイル名はcredentialsだったような。

これが完了すると、~/.aws/credentialsっていうファイルが出来ます。 中身はこんな感じ。

[default]
aws_access_key_id = xxxxxxxxxx
aws_secret_access_key = yyyyyyyyyy

これでAWS CLIが使えるようになったので、ついにServerless Frameworkをインストールします。

※Serverless Frameworkをインストールするにはnpmが必要です。
npmって何?ってひとはこちらを参考にしてください。

Serverless Frameworkをインストール

npm install -g serverless

こんな感じになればインストール完了です。

└─┬ serverless@1.1.0 
  ├── agent-base@2.0.1 
  ├── ansi-regex@2.0.0 
  ├── ansi-styles@2.2.1 
  ├─┬ archiver@1.1.0 
  │ └── async@2.1.1 
...

これでserverlessコマンドが使えるようになったんですが、いちいちserverlessとか長いしタイポしそうなんで、
slsって短縮コマンドも用意されています。

早速プロジェクトを作成しましょう!

Serverless Frameworkでプロジェクトを作成

mkdir serverless-chatwork
cd serverless-chatwork
sls create --template=aws-nodejs

するとこんな感じにカッコイイロゴが表示されれば、プロジェクトの作成は完了です。

Serverless: Generating boilerplate…
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.1.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name

nodejs?僕パイソニスタなんだけど。って人はpython版で作成してください。 templateのaws-nodejsをaws-pythonに変更すればOKです。

ではプロジェクトの設定をしていきましょう。

Serverless Frameworkプロジェクトの設定

serverless.ymlというファイルがあるので以下のように編集します。

service: serverless-chatwork # プロジェクト名です。好きな値をどうぞ。

provider:
  name: aws
  runtime: nodejs4.3
#  stage: dev # デプロイする環境。デフォルトではdevになってる。開発環境なんていらんよ。って人はproduction等に変更しましょう。
  profile: default # ~/.aws/credentialsの中の[]の中の文字です。defaultの場合はこの行削除してもいいです。
  region: ap-northeast-1 # AWSのリージョンです。東京に変更したい場合はこんな感じ。

functions:
  push: # 作成するLambdaの名前
    handler: handler.push # handler.js内の関数名
    events:
      - http:
          path: v1/push # API Gatewayのエンドポイント v1とかバージョンを作っとくと大規模な改修の際に便利かも?
          method: post # get, post, put, delete等
          cors: true # これ設定するとCORSが有効になって外部からも叩けるよ

plugins:
  - serverless-run-function-plugin # あとで説明するけど、これ入れとくとローカルでテストできます。

上の設定で出て来るserverless-run-function-pluginですが、デプロイする前にローカルでAPIのテスト出来るようになるので入れておきましょう。

serverless-run-function-pluginのインストール

npm install -g serverless-run-function-plugin

早速ローカルでテストを実行する前に、handler.jsも修正しましょう。 handler.jsはLambdaの中身になります。

handler.jsとevent.jsonの設定

今回は以下のように修正して下さい。 簡単に補足するとevent.jsonはコマンドから実行するときにhandler.jsのeventに任意の値を設定するためのものです。

handler.js

'use strict'; // 厳しいモードでいきましょう。

const request = require('request');

const CHATWORK_TOKEN = 'チャットワークAPIを利用するためのトークン';

module.exports.push = (event, context, callback) => {
  var response = {
    statusCode: 200,
    // CORSを有効にする場合は設定必要。*は全てなので許可する範囲を設定したい人は修正してください。
    headers: {
      "Access-Control-Allow-Origin" : "*"
    },
  };

  // postでjson文字列を送信した場合、受け取ったデータは全てevent.bodyに入っています
  const post = JSON.parse(event.body);

  // room_idは必須にする
  if(typeof post.room_id == 'undefined'){
    response.statusCode = 400;
    response.body = JSON.stringify({ message: 'room_idを指定して下さい。' });
    return callback(null, response);
  }

  // textは必須にする
  if(typeof post.text == 'undefined'){
    response.statusCode = 400;
    response.body = JSON.stringify({ message: 'textを指定して下さい。' });
    return callback(null, response);
  }

  // チャットワークにチャット送信
  pushToChatwork(post.room_id, post.text);

  response.body = JSON.stringify({ message: '送信完了' });
  callback(null, response);

};

// チャットワークにチャット送信
const pushToChatwork = (room_id, text) => {
  var options = {
    url: 'https://api.chatwork.com/v1/rooms/' + room_id + '/messages',
    headers: {
      'X-ChatWorkToken': CHATWORK_TOKEN
    },
    form: { body: text },
    json: true
  };
  request.post(options);
}

event.json

{
  "body": "{\"room_id\": \"チャットワークのルームID\", \"text\": \"投稿したい文字列\"}"
}

また、今回requestパッケージを使用したので、npmの下準備をしてインストールしましょう。

npm init

Press ^C at any time to quit.
name: (serverless-chatwork) 
version: (1.0.0) 
description: Chatwork API with Serverless Framework
entry point: (handler.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Users/shunkushigami/tmp/serverless-chatwork/package.json:

{
  "name": "serverless-chatwork",
  "version": "1.0.0",
  "description": "Chatwork API with Serverless Framework",
  "main": "handler.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

requestのインストール

npm install request --save

これでnode_modulesというディレクトリが出来て、デプロイ時に一緒にアップしてくれます。

ローカルでテストを実行

sls run -f push

-fの後に実行する関数名を指定すると実行してくれます。

こんな感じに表示されて、

Serverless: -----------------
Serverless: Success! - This Response Was Returned:
Serverless: {
    "statusCode": 200,
    "headers": {
        "Access-Control-Allow-Origin": "*"
    },
    "body": "{\"message\":\"送信完了\"}"
}

指定のルームにチャットが届けば成功です!

今のままではローカルでしか実行できないので、いよいよデプロイします。

Serverless FrameworkでAWSにデプロイする

sls deploy

たったのこれだけです。
Serverless Frameworkやばいですね。 これだけでCloudFormationを作成してくれて、それらをS3にアップしてくれて、Lambda作ってくれて、API Gateway作ってくれます。

こんな感じでエンドポイントが表示されればデプロイ完了です。

Serverless: Creating Stack…
Serverless: Checking Stack create progress…
..
Serverless: Stack create finished…
Serverless: Deprecation Notice: Starting with the next update, we will drop support for Lambda to implicitly create LogGroups. Please remove your log groups and set "provider.cfLogs: true", for CloudFormation to explicitly create them for you.
Serverless: Packaging service…
Serverless: Uploading CloudFormation file to S3…
Serverless: Uploading service .zip file to S3…
Serverless: Updating Stack…
Serverless: Checking Stack update progress…
.................
Serverless: Stack update finished…

Service Information
service: serverless-chatwork
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  POST - https://xxxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/v1/push
functions:
  serverless-chatwork-dev-push: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxxxx:function:serverless-chatwork-dev-push

では、AWSにアップされたようなのでコマンドから実際にエンドポイントが効いているか試してみましょう。

Serverless FrameworkでAPIをコールする

sls invoke -f push -p event.json

このコマンドで実際にリモートのAPIをevent.jsonの内容でコールしてくれます。
-pで使用するevent用jsonを指定します。

以下のように表示されて、実際にチャットが届けば完了です!

{
    "statusCode": 200,
    "headers": {
        "Access-Control-Allow-Origin": "*"
    },
    "body": "{\"message\":\"送信完了\"}"
}

作ったはいいけど、他の人に試してもらうためには以下のように教えてあげましょう。

jQueryから試す

jQueryマイスターには以下で試してもらいましょう。

var data = {
    room_id: "チャットワークのルームID",
    text: "投稿したい文字列"
}
$.ajax({
    url: "生成したエンドポイント",
    type: "POST",
    dataType: "JSON",
    data: JSON.stringify(data)
});

Curlから試す

コマンドライン大好きな人には以下で試してもらいましょう。

curl 生成したエンドポイント -X POST -d "{\"room_id\": "チャットワークのルームID", \"text\": \"投稿したい文字列\"}"

まとめ

以上、長々と書きましたが、Serverless Frameworkを実践的に使用する方法を解説しました。
Serverless Frameworkとかサーバーレス自体に興味ある人はぜひ試してみて下さい。

次回以降はDynamoDBとの連携方法や、Lambdaの定期実行等も書いていきたいと思いますので、乞うご期待!

お疲れ様でした。