Slide 1

Slide 1 text

マーケティングに強いCTOが語る技術未来とElixir 第1回 . 2020年の後、訪れるIT投資激減と. システム崩壊、そして救世主Elixir. 2018/02/15 ver 0.5作成 . 2018/02/23 ver 0.9作成 . 2018/02/25 ver 1.0作成 . 2018/03/04 ver 1.1作成(enPiT everi update) 2018/03/06 ver 1.2作成 .

Slide 2

Slide 2 text

1 プログラマ歴36年 / XPer歴18年 / 福岡 技術顧問 (3社) AIジョブカレ 福岡代表 / enPiT (文科省 社会人IT育成) 講師 IT企業2社経営 。 森 正和 |> 。 Elixirコミュニティ「fukuoka.ex」 福岡 理学部 / IAI Fukuoka / 「通常の3倍」福岡 主催 「量子コンピュータ by Blueqat」 / 「OpenQL」 福岡代表 福岡Elixirプログラマ / 重力プログラマ my favotite technology & implements. Twitter/Qiita/Github @piacere_ex

Slide 3

Slide 3 text

2

Slide 4

Slide 4 text

3 福岡に移住して 1年が過ぎました

Slide 5

Slide 5 text

4 そんな福岡での 普段の活動

Slide 6

Slide 6 text

5 2018/2/23 福岡Elixirコミュニティ イベント fukuoka.ex MeetUp #5 ~福岡におけるElixirの進化~

Slide 7

Slide 7 text

福岡Elixirコミュ「fukuoka.ex」主催→採用企業増加 告知から9時間で満席、隔月定期開催 (偶数月) 次回#6は4月 昨年6月から半年 続けた結果、告知 から9時間で満席 になる人気コミュに 育ちました ①福岡Elixirプログラマ 前回は、福岡での Elixirプロダクション 採用事例を紹介 国内・海外含め、 fukuoka.exでしか 得られない尖り具合 https://techjin.connpass.com/event/79311/

Slide 8

Slide 8 text

Elixirとは?…「データ変換」「並行・分散」特化の言語 Elixirは、CSVファイルやDBデータ、JSON、バイナリデータ等の データを受け取り、パターンマッチし、加工・変換し、Webや APIを高速開発するのに最適な関数型プログラミング言語です また、扱うデータが全てイミュータブルなため、副作用が無く、また 大量のプロセスを起こしてもオーバーヘッドが極端に小さいため、 並行・分散処理に最も適したプログラミング言語でもあります iex> IO.puts( "hoge" ) メッセージパッシング IO処理 IOサーバプロセス ①福岡Elixirプログラマ

Slide 9

Slide 9 text

Elixirが持つ「7つの顔」 Elixirは、以下の「7つの顔」を持っており、この全てを備えている プログラミング言語は、Elixir以外には、見当たりません 低レイテンシ 容易に マルチコア並列 耐障害性 軽量マルチ プロセス 初心者に優しい ※「経験者」に優しい 訳では無い シンプルで強力 高い生産性 少コードで高機能 ①福岡Elixirプログラマ

Slide 10

Slide 10 text

fukuoka.exは「実際に動くコード」でライブデモする会 地味に女子率、高し(^o^) ①福岡Elixirプログラマ

Slide 11

Slide 11 text

SlideShareに入門編、QiitaにPgコラムを多数寄稿 ↓SlideShareで「Elixir」打つと上位を複数独占状態 (他スライドは、Tokyo.exメンバー等、大抵知り合い) ↓AIもElixirで作ります Qiitaコラム連載中はトップ独占→ ①福岡Elixirプログラマ

Slide 12

Slide 12 text

正月休み中、オープンソースを4本+α版2本リリース 量子コンピュータ シミュレータ (一昨日、福岡で登壇) Google Drive APIラッパー (狙え公式採用) bitFlyerアクセッサ (ビットコイン自動取引) Elixirの小粒でピリリ なユーティリティ群 データサイエンス プラットフォーム基盤 データサイエンス プラットフォーム基盤 も作ってます ①福岡Elixirプログラマ

Slide 13

Slide 13 text

12

Slide 14

Slide 14 text

13 ②重力プログラマ 理論から入り、数式もガッツリ 読み解き、プログラミングする

Slide 15

Slide 15 text

14 ②重力プログラマ

Slide 16

Slide 16 text

15 ②重力プログラマ 数式をプログラム化し、 実際に動かして体感する

Slide 17

Slide 17 text

16 ②重力プログラマ 数式がビジュアルやムーブ として形になる様を披露

Slide 18

Slide 18 text

PyFukuokaで、第2回「重力波をJupyterで解析」 ②重力プログラマ

Slide 19

Slide 19 text

18 ②重力プログラマ

Slide 20

Slide 20 text

19 ②重力プログラマ

Slide 21

Slide 21 text

Qiita Advent Calendarで複数の上位ランクイン ②重力プログラマ

Slide 22

Slide 22 text

21 ②重力プログラマ

Slide 23

Slide 23 text

22 2017/12/01 福岡AI・MLコミュニティ イベント 第3回「福岡x人工知能x…」 ~Kerasディープラーニング プログラミング入門~

Slide 24

Slide 24 text

AI/MLコミュ「福岡x人工知能」主催→大人気化 次回#5は5月末 告知から33分で満席、隔月 (奇数月) 定期開催 告知から1時間以内 に満席で、開始した 半年前から毎回、 常にキャンセル待ち (最大倍率3.8倍) の人気イベント ③AI・MLデータサイエンティスト https://techjin.connpass.com/event/76616/

Slide 25

Slide 25 text

③AI・MLデータサイエンティスト ほぼ理論や数学を使わず AI・MLプログラミングの パラダイムを体感してもらう

Slide 26

Slide 26 text

AI入門 第3回 「数学苦手でも何とかなる Kerasディープラーニング開発」 2017/08/15 ver0.5作成 2017/08/15 ver0.9作成 具体的なコードと、動くアプリで セッションやっています ③AI・MLデータサイエンティスト

Slide 27

Slide 27 text

AI・MLプログラミング入門@「福岡x人工知能x…」 ③AI・MLデータサイエンティスト

Slide 28

Slide 28 text

27

Slide 29

Slide 29 text

2017/10創業、マーケティングPF「b→dash」を提供 Forbesの「世界を変える スタートアップ100選」登場 国内ITスタートアップでは 最高額の32億円を調達 ④TechJIN CTO

Slide 30

Slide 30 text

b→dashが持つデータを分析するPFもElixirで開発 ④TechJIN CTO グラフや数値の変動・傾向から、 顧客がb→dash利用に戸惑って いないかを検出したり、顧客への コンサルティングを改善するツール Elixir 100%で超高速開発 (5MDで初期版リリース) 現在、SQL入りのコンフィグを 編集するだけで指標拡張が可能

Slide 31

Slide 31 text

30 他にも、こんなことしてます ・トレードシステムの開発・運用 ・天体シミュレータ開発 ・東京のIT企業 (2社) 経営 ・お金のために職業を選ぶ必要 が無くなる子供向け教材開発

Slide 32

Slide 32 text

31 福岡で1年活動し 最先端ITを実現可 と判断したので…

Slide 33

Slide 33 text

32 これら活動と 並行して今年から 新たな活動を始動

Slide 34

Slide 34 text

1/11から、福岡での技術顧問、はじめました ⑤福岡 技術顧問 以下の福岡IT企業 (2社) の技術顧問に就任しました 主に、PJ推進支援と、Elixir導入・運用支援、エンジニア 意識向上・評価基準を提供 ※福岡企業で興味あれば下記に連絡を カラビナテクノロジー株式会社 地元の中小企業のIT化から、大規模流通業の SI開発まで、手広く手掛ける、福岡ITの急先鋒 有限会社デライトシステムズ 販売管理の自社パッケージ提供と、AWS/GCP を中核とした高性能Webシステム開発に定評ある https://twitter.com/piacere_ex の「ダイレクトメッセージを送る」で「技術顧問、興味有」と

Slide 35

Slide 35 text

1/19、「福岡 理学部」コミュニティを有志で発足 ⑥福岡 理学部 LINE Fukuoka、Fusic、 ベガ・コーポレーション、TechJIN といった、福岡の数学・物理に 強いエンジニアが、仕事に関係 有る無しにこだわらず、好きな 分野で好き勝手にLTしまくるw 実績ゼロのイベントにも関わらず、告知から3日で満席 https://fukuoka-science.connpass.com/event/75947/

Slide 36

Slide 36 text

3/2、東京の量子コンピュータ達人を福岡招致に成功! ⑦福岡 量子コンピュータ 1講演、¥32,400と高額な講師が、福岡で無料講演 しかも今回講演で終わらず、 今後も継続して福岡での 量子コンピュータアプリ開発 を支援し続けていただく予定 https://qnn.connpass.com/event/76091/

Slide 37

Slide 37 text

3/26から、福岡でAI学校の講師、はじめます ⑧福岡 AI学校 講師 AI権威の松尾研出身で名著「詳解ディープラーニング」 の著者、巣籠さんも監修するAIスクールで福岡代表に https://www.aijobcolle.com/

Slide 38

Slide 38 text

fukoka.exが取材を受けた記事が4月くらいに出ます ⑨Elixirアドバイザーズ enPiT everiで事業担当の北九大 山崎先生と、私を 含む4名 (下記、赤囲み) で、福岡でElixir採用企業 100社を目指し、Elixirの無料相談窓口を開始予定 https://twitter.com/piacere_ex の「ダイレクトメッセージを送る」で「福岡Elixir相談有」と enぺだーし 複数言語の性能面と マルチコア活用に特化 ゆじかわ 他言語からElixirへの 転向とSI開発が専門 piacere ElixirのSIとFW開発 を得意とする経営者 ざっきー (山崎先生) Elixirに特化したVMを 作るカーネルハッカー

Slide 39

Slide 39 text

家賃・食費安く、幸福度高い福岡エンジニアしません? ⑩福岡エンジニア移住PJ fukuoka.ex/福岡x人工知能x…/福岡 理学部と 福岡IT企業数社 (ベンチャーから大手まで) とコラボで、 IT案件と都心から移住したいエンジニアのマッチング を展開し、Elixirを始めとする各種先端技術に携わる チャンスを提供 ※ちなみに最初の3人までは無料でご紹介(^o^) https://twitter.com/piacere_ex の「ダイレクトメッセージを送る」で「福岡移住希望」と

Slide 40

Slide 40 text

3/16、夢の「重力と宇宙」に特化したイベント打ちます! ⑪重力・宇宙を愛する集い ずっとずっと夢だった「重力と宇宙」だけにテーマ特化した イベントを開催!!天体研究するJK、LINEデータサイエン ティスト、衛星を飛ばすベンチャー他、物凄い布陣で実現 https://fukuoka-science.connpass.com/event/81220/

Slide 41

Slide 41 text

40 やたら長い 自己紹介でしたが

Slide 42

Slide 42 text

41 ここから本題

Slide 43

Slide 43 text

42 1. 2020年の後に訪れるIT・SI業界の変化 2. 既存のIT技術の何がイケてないのか? 3. Elixir≠「違う言語」、==「違うパラダイム」 4. SIやプロダクション開発におけるElixir ① Webアプリケーション開発 ② DB操作 ③ 外部API呼出、暗号化 ④ バッチ ⑤ APIサーバアプリケーション開発 ⑥ 監視/ログ/耐障害性 ⑦ マルチコア並列処理 ⑧ AI・ML呼出&データサイエンス 5. この1年、福岡で爆誕するElixirムーブメント 目次

Slide 44

Slide 44 text

43 1.2020年の後に訪れるIT・SI業界の変化

Slide 45

Slide 45 text

44 1.2020年の後に訪れるIT・SI業界の変化 現在、バブルに入っている日本経済は、東京オリンピックの特需 が無くなった後の2020~2022年頃、大きな不景気を迎えるの では無いかと予測しています (この経済動向は、比較的、長い話になるので、気になって仕方が無い方 のみ、懇親会で聞きに来てください) その結果、事業会社のIT投資は激減※し、都心からの下請け でIT・SI収入の70%以上が構成される福岡は、当然、影響を 受け、PJのストップと、企業倒産の多発が考えられます ※IT投資に限らず、アウトソーシングからインソーシングに切り替える企業の増加もあります SI業界全体としては、現在の1/2~1/5の「コストダウンの波」 が訪れ、従事できる人材が減り、その結果、「人手不足」という 形に現れる、大きな混乱期へと突入することでしょう

Slide 46

Slide 46 text

45 1.2020年の後に訪れるIT・SI業界の変化 一方で、企業や都市、その他各所から取得できるデータ量は、 現在の200~500倍にも膨れ上がることが予想されます これは、主に以下の要因によるものです ① エンドユーザの趣向の広がりに伴う企業データの増加 ② IoTデバイスやセンサーのあらゆる場所への設置 ③ 衛星データ/宇宙データといった、新たなデータ活用 こうした大量データ需要に対し、既存の「クラスタ追加」「クラスタ 性能アップ」といったデータ増加に追いつけないスケーラビリティ では、多発するシステムダウンに怯えることとなるでしょう また、本来は大量データを捌けるマルチコアやメニーコアを活用 する言語を持っていない、という事実を目の当たりにするでしょう

Slide 47

Slide 47 text

46 2.既存のIT技術の何がイケてないのか?

Slide 48

Slide 48 text

47 2.既存のIT技術の何がイケてないのか? マトモに説明すると、100時間位かかる (笑) ので、メッチャ要約 すると、以下3点に集約されます ① 2003年に頭打ちしたシングルコア性能に依存し、マルチ コア/メニーコアが持つポテンシャルを引き出せていない ② 「性能観点」や「耐障害性観点」、「安定運用の観点」で プログラミング言語を選定しておらず、「構文」や「入門が 容易」、「組める人が多い」、「情報が豊富」といった、「知 名度」もしくは「趣味要素」※で選定している ③ 10~20年後の未来における技術と経済の発展を想定 した上でのテクノロジーやエンジニアの立ち位置をイメージ できていない ※知名度・趣味要素は、選定上、大事なポイントではあるが、第一優先では無い

Slide 49

Slide 49 text

48 2 【補足】 .マルチコアを使いこなすのは難しい? そもそも、マルチコアを使いこなせていない現状と、マルチコア活用 にどのような課題があるのかの実態を紐解きます 以下の観点で、マルチコア活用は現在、ハードルが高めです ① 全マルチコアを使い切るには、各コアへの均等な負荷の 分散が必要となるが、その前提としての処理分割が困難 ② 複数コアが同時にメモリーアクセスすることによる性能劣化 ③ 各コア毎に処理を独立させるには、マルチスレッドが有効 だが、マルチスレッドの扱い自体に難しさがある 再掲: Elixir入門#8より

Slide 50

Slide 50 text

49 2 【補足】 .マルチコアを使いこなすのは難しい? ①マルチコア向けの処理分割が必要 全マルチコアを使い切るには、各コアが単独で実行できる単位に 「処理分割」をしなければなりません それができない場合、各コア毎に処理を分担させることができず、 マルチコアの処理性能を使いこなすことは不可能です 並列計算の性能向上限界を説明する「アムダールの法則」でも、 逐次処理単位が充分に小さくないと、コア数 増加の性能向上が得られないとしています また「処理の分割」を実現するプログラミング 言語やライブラリは、マルチコア化に対して、 充実しているとは言えない状況です 再掲: Elixir入門#8より

Slide 51

Slide 51 text

50 2 【補足】 .マルチコアを使いこなすのは難しい? ②同時メモリーアクセスすると性能劣化の懸念 仮に①がクリアされ、マルチコア向けに処理分割できたとしても、 複数コアから同じアドレス帯のメモリーを同時アクセスした場合、 キャッシュが有効に活用できず、下手すると、シングルスレッドより も性能劣化する危険性があります これは、一度更新されたメモリー内容が、変更可能 (mutable) であることに大きな原因があります 有効な対策の1つとしては、一度更新したメモリーを変更不可 (immutable)にすることですが、オブジェクト指向言語は、状態 を保持し、変更することが一般的なプログラミングなため、 これの 実現には、多大なプログラミング統制が必要となり、困難です 再掲: Elixir入門#8より

Slide 52

Slide 52 text

51 2 【補足】 .マルチコアを使いこなすのは難しい? ③マルチスレッドの扱いが難しい 仮に①②がクリアされ、処理分割かつimmutableが実現できた としても、「マルチスレッド化」には、以下のような難しさがあります i. 処理 (ないしはコード) が複雑になりがち ⚫ シングルスレッドを前提としたプログラミング言語では、マルチスレッドはライブラリ等 で補完されるため、ダイレクトな記載ができず、スパゲティコードを作りがち ii. 状態の排他制御に気を使わないと競合が発生する ⚫ オブジェクト指向言語では、オブジェクトに状態を持つため、状態を変更する際に ロックしないと競合が発生してしまう (そして、ロック管理は複雑になりがち) iii. スレッドの起動自体にメモリー負荷がかかる ⚫ オブジェクト指向言語でのスレッド起動は、状態保持のために、スレッドのスタック やヒープが確保されるが、このメモリー使用量が大きく、スレッドを気軽に使えない iv. デバッグが非常に困難となる ⚫ 状態で挙動が変わるマルチスレッドのデバッグは、タイミング依存し、非常に困難 再掲: Elixir入門#8より

Slide 53

Slide 53 text

52 3.Elixir≠「違う言語」、==「違うパラダイム」

Slide 54

Slide 54 text

53 3.Elixirが持つ「7つの顔」 Elixirは、以下の「7つの顔」を持っており、この全てを備えている プログラミング言語は、Elixir以外には、見当たりません 低レイテンシ 容易に マルチコア並列 耐障害性 軽量マルチ プロセス 初心者に優しい ※「経験者」に優しい 訳では無い シンプルで強力 高い生産性 少コードで高機能

Slide 55

Slide 55 text

54 3.既存のIT技術を超えるElixirの技術 既存ITでイケてない以下3点を、Elixirは華麗にクリアしています ① マルチコア/メニーコアが持つポテンシャルをいとも簡単に 引き出せる (通常コードの軽微修正でマルチコア化可) ② 「性能観点」や「耐障害性観点」、「安定運用の観点」は、 ElixirとErlangVMを選んだ時点で内包されており、シス テムの運用観点はクリア済み ③ 10~20年どころか、80年後 (2100年) の技術と経済 の未来を予測する、IT道35年/SI道20年の技術者が、 業界の酸いも甘いも、大規模もアジャイルも噛み分けた 上で、長旅の末に到達したプログラミング言語がElixir Elixirへの入門は、「目的に合わせてプログラミング言語を選ぶ」 というプロの領域を更に超え、「プログラミングという行為が異なる パラダイムに移行している」ことを実感する第一歩となるでしょう

Slide 56

Slide 56 text

55 3.C10K問題を解決できる高速Web「Phoenix」 ElixirのWebプラットフォームであるPhoenixの他プラットフォーム との性能比は、以下のような感じで、シングルスレッドのスピードが 売りのGo言語と比べても、なかなか良い勝負をしています マルチプロセス/マルチコア性能については、以下をご覧ください https://www.slideshare.net/YoshiiroUeno/elixir-go-c-scalanodejs WebSocket性能比 0 10000 20000 30000 40000 50000 60000 Throughput (req/s) Webページビュー性能比 http://postd.cc/websocket-shootout/ https://github.com/mroth/phoenix-showdown

Slide 57

Slide 57 text

56 3.Excelを扱う感覚で本格プログラミング 言語的な側面でも、とっつきやすく簡単※で、通常プログラミング 言語と言えば、キチっと学ばないと使いこなせないのに対し、 Elixirは、Excelを扱う感覚で、本格的なWebアプリケーションや APIなどをプログラミングしていけます ※Elixirは、「関数型言語」という部分で、オブジェクト志向言語に慣れた方には、ハードル が高い面があるのは否めませんが、一方で、関数型言語は「Excelのようなもの」として 覚えていくと、意外とスンナリ入るので、初心者にとっては低いハードルとして映るでしょう このあたりは、今後リリース予定の「Excelを扱うようにElixirに入門する」シリーズで検証 していこうと思います iex> [ 123, 999, 54 ] |> Enum.sort [54, 123, 999] ==

Slide 58

Slide 58 text

57 4.SIやプロダクション開発におけるElixir

Slide 59

Slide 59 text

58 4.SIやプロダクション開発におけるElixir ここからは、具体的に、SIやプロダクション開発の中で、Elixirを 使う上での全体像として、以下の項目に分けてお伝えします ① Webアプリケーション開発 ② DB操作 ③ 外部API呼出、暗号化 ④ バッチ ⑤ APIサーバアプリケーション開発 ⑥ 監視/ログ/耐障害性 ⑦ マルチコア並列処理 ⑧ AI・ML呼出&データサイエンス この説明に入る前に、福岡において、既にElixirをプロダクション 採用している各種企業をご紹介することで、リアリティあるイメージ として共有するところから始めたいと思います

Slide 60

Slide 60 text

59 福岡でのElixir プロダクション採用

Slide 61

Slide 61 text

60 4.福岡におけるElixirプロダクション採用事例 製造業/流通業/情報サービス業などのスタンダードなSI案件 の構築を、Elixir+Phoenix (フロントはAngular) で実現 AWS EC2上のDockerに、Elixirをインストールすることで運用 しており、利用DBはPostgreSQL PythonやPHPメインだったエンジニアが、Elixirを学び、「ソニック ガーデン方式」のアジャイル開発体制へと移行した事例 (今年は、大規模案件も予定されています)

Slide 62

Slide 62 text

61 4.福岡におけるElixirプロダクション採用事例 山登りアプリで有名な自社サービスの「検索サジェストサーバ」を Elixir+Phoenix+ElasticSearchで動作させているが、1年 近く、ダウンしたことが無く、放ったらかしでの運用を実現 近日、画像メディアサーバをリリースするが、こちらは画像アップ ロードによる負荷で他APIが詰まるのを回避することが目的 AWS EC2上のDockerに、Elixirをインストールすることで運用 しており、利用DBはMongoDB 複数サービスの運用負荷をElixirで低減した事例

Slide 63

Slide 63 text

62 4.福岡におけるElixirプロダクション採用事例 アパレル、旅行、金融などのBtoC用マーケティング強化プロダクト 「b→dash」が蓄積したデータを分析する「活用スコアシステム」 を、Elixir+Phoenix (フロントはPlainJS+jQuery) で構築 AWS EC2に直接Elixirをインストールして運用しており、利用 DBはMySQL/Redshift 性能問題を抱えるRuby on RailsからElixirに変更したことで、 性能向上と安定性向上を両立したビッグデータサイエンス事例

Slide 64

Slide 64 text

63 4.福岡におけるElixirプロダクション採用事例 LINEのメッセージ「LEGY (LINE Event GatewaY)」は、 Erlangで書かれており、2012年以来、LINEの根幹を支える 高性能/安定性を実現しています (元々nginxだったが、共有 メモリのセグフォ乱発でErlangに移行) 「Elixir Conf Japan 2017」の協賛企業でもあります 福岡社内では、Elixirを学習するメンバーが増えており、今年は 勉強会やイベント開催を博多で行う機会も増える見込み

Slide 65

Slide 65 text

64 4.福岡におけるElixirプロダクション採用事例 上記の他にも、FusicやGMOペパボ、サーキュレーションのような、 福岡でも知名度ある企業がElixirを採用する動きが高まっており、 今年の福岡Elixir界隈は、賑わいを見せようとしています ~半年間、頑張り続けて良かった(^o^)~ 今後、Elixir採用企業様は、fukuoka.exで積極的に取り上げ させていただき、取材やイベント開催などのメディア展開でご紹介 しますので、採用検討段階からでも、ぜひお声掛けくださいませ

Slide 66

Slide 66 text

65 全国と世界のElixir プロダクション採用

Slide 67

Slide 67 text

66 4.福岡以外のElixirプロダクション採用事例 福岡以外では、上記の国内企業および海外の企業が、Elixirを プロダクション採用しています (銀行や証券でも採用されます) その規模は、現在、全世界で約200社程度となります http://elixir-companies.com/

Slide 68

Slide 68 text

67 4.事前準備:Elixirの予備知識 Elixirは、後発なモダン言語ということもあり、プログラミング言語 に必要な大抵のモジュール/ライブラリは、ビルトインされており、 他言語とくらべても、プログラミング中に困ることはさほどありません

Slide 69

Slide 69 text

68 4.事前準備:Elixirの予備知識 Elixirのライブラリシステムである「Hex」は、コマンドラインだけで、 ライブラリ登録やオンラインドキュメントのアップロードが可能です また、2015年当時は、7,000件程度しか無かったライブラリも、 2018年2月現在、約34,000件と、たった2~3年間で4.8倍 も増えている状況です

Slide 70

Slide 70 text

69 4.事前準備:Smallexのインストール 本スライドでは、Elixirライブラリ「Smallex」を前提としたコードが 幾つか出てきますので、Elixirプロジェクトを作る度、インストール を行ってください 以下コマンドでモジュールを取得します (要ネット接続) defmodule Sample.Mixfile do … defp deps do [ { :smallex, "~> 0.1.1" }, ] end end # mix deps.get

Slide 71

Slide 71 text

70 4-①.Webアプリケーション開発

Slide 72

Slide 72 text

71 4-①.Webアプリケーション開発 ElixirでWebアプリケーション開発する際、以下2種類の選択肢 があります ① Ruby on Railsに似た実装の「Phoenix」を使う ② 最低限のWebサーバ機能を持つ「Cowboy」を使う 「使わない余計な機能があると気になって仕方無い」などの特殊 な理由が無い限り、ページテンプレート機能やMVCが充分整備 されたPhoenixがオススメです

Slide 73

Slide 73 text

72 2.Phoenixのインストール Phoenixをインストールします (要ネット接続) Phoenixプロジェクトを作成します (要ネット接続) 作成したプロジェクトでPhoenixサーバーを起動します # mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez # mix phx.new sample --no-brunch # cd sample # iex -S mix phx.server 掲載スペースの関係で2行になっていますが、 URLも続けて入力してください PJ名には、英大文字を指定したり、 「web」という名前を付けると エラーないしはビルド途中でコケることがあります 再掲: Elixir入門#3より

Slide 74

Slide 74 text

73 2.Phoenixのインストール ブラウザで「http://localhost:4000」にアクセスすると、 Phoenixで作られたWebページが見れます 再掲: Elixir入門#3より

Slide 75

Slide 75 text

74 4-②.DB操作

Slide 76

Slide 76 text

75 4-②.DB操作 DBアクセスは、各種DB接続/操作をラップしてくれるモジュール 「Ecto」が便利です Ectoの使い方には、以下3種類があります ① mix phx.gen.html等で自動生成されるMVCを使う (Ruby on RailsのActive Recordに似ている) ② Ectoの「Query DSL」を使う ③ EctoにSQLを渡し、直接実行する

Slide 77

Slide 77 text

76 4.WebアプリからDB操作する モデルを格納するDBを作成します DBが追加されていることを確認します # mix ecto.create # sudo -u postgres psql -l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -------------+----------+----------+-------------+-------------+----------------------- sample_dev | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres (4 rows) 再掲: Elixir入門#3より

Slide 78

Slide 78 text

77 4.WebアプリからDB操作する Webアプリ用のモデル生成を行います 今回は、titleとbodyの2項目を持ったモデルを作ります なお、第3~5引数は、以下で使われます ⚫ 「DbAccessor」…lib/sample/配下フォルダ名、テーブル操作用モジュールの名前 ⚫ 「Post」…上記フォルダ内に置かれるテーブル定義モジュールの名前 ⚫ 「posts」…このWebアプリを示すURLのディレクトリ名 この後、コマンド終盤に記載の、lib/sample_web/router.ex へのパス追加と、モデルのマイグレーションを行います # mix phx.gen.html DbAccessor Post posts title:string body:text … Add the resource to your browser scope in lib/sample_web/router.ex: resources "/posts", PostController Remember to update your repository by running migrations: $ mix ecto.migrate 再掲: Elixir入門#3より

Slide 79

Slide 79 text

78 4.WebアプリからDB操作する lib/sample_web/router.exへのパス追加を行います モデルのマイグレーションを行います # mix ecto.migrate defmodule SampleWeb.Router do use SampleWeb, :router … scope "/", SampleWeb do pipe_through :browser # Use the default browser stack get "/", PageController, :index resources "/posts", PostController end … end 再掲: Elixir入門#3より

Slide 80

Slide 80 text

79 4.WebアプリからDB操作する マイグレーションの結果、テーブル追加されるので、確認します # sudo -u postgres psql psql (9.3.18) Type "help" for help. postgres=# ¥c sample_dev You are now connected to database “sample_dev" as user "postgres". sample_dev=# ¥d posts Table "public.posts" Column | Type | Modifiers -------------+-----------------------------+---------------------------------------------------- id | integer | not null default nextval('posts_id_seq'::regclass) title | character varying(255) | body | text | inserted_at | timestamp without time zone | not null updated_at | timestamp without time zone | not null Indexes: "posts_pkey" PRIMARY KEY, btree (id) 再掲: Elixir入門#3より

Slide 81

Slide 81 text

80 4.WebアプリからDB操作する Phoenixサーバを起動します ブラウザで「http://localhost:4000/posts」を表示すると、 「Title」「Body」がリストされるページが表示されます # iex -S mix phx.server 再掲: Elixir入門#3より

Slide 82

Slide 82 text

81 4.WebアプリからDB操作する 「New post」から、新たなアイテムを追加できます 再掲: Elixir入門#3より

Slide 83

Slide 83 text

82 4.WebアプリからDB操作する 追加後は以下の通りです 「Show」「Edit」「Delete」で追加されたアイテムを編集できます 再掲: Elixir入門#3より

Slide 84

Slide 84 text

83 4-②.バリデーションチェック mix phx.gen.html等で生成されたスキーマ用モジュールには、 必須バリデーションチェックが含まれているので、必須チェック不要 な場合は、対象を削除してください defmodule Sample.DbAccessor.Post do use Ecto.Schema import Ecto.Changeset alias Sample.DbAccessor.Post schema "post" do field :title, :string field :body, :string timestamps() end @doc false def changeset(%Post{} = post, attrs) do post |> cast(attrs, [:title, :body]) |> validate_required([:title, :body]) end end lib/sample/db_accessor/post.ex

Slide 85

Slide 85 text

84 4-②.バリデーションチェック 必須チェック以外にも、フォーマットチェックや長さチェック、数値の 範囲チェック、値一致チェックなど、さまざまなバリデーションチェック が用意されています 詳細は、以下をご覧ください https://qiita.com/cohki0305/items/53c99c150bfe29cac16a

Slide 86

Slide 86 text

85 4-②.スキーマ変更 mix ecto.gen.migrationと、mix ecto.migrateを使って、 テーブル名変更や列名変更/削除、インデックス変更/削除が 行えます 詳細は、以下をご覧ください https://qiita.com/darui_kara/items/7f07b07771089c0607a8 https://qiita.com/piacere/items/7a6fff43deecc7ed9c53

Slide 87

Slide 87 text

86 4-②.Query DSLを使う Ectoは、SQLライクなDSL (専用言語) を提供しており、DBの 操作時、複数のwhere句をパイプで繋ぐ操作をElixirの構文で 書く、といったことができます 詳細は、以下をご覧ください https://elixirschool.com/ja/lessons/specifics/ecto/

Slide 88

Slide 88 text

87 4-②.SQLを直接実行する SQLを直接実行するには、Ecto.Adapters.SQL.query()を 使います (性能重視のselectを書きたいケース等で重宝します) 以下のようなミニモジュールを用意しておくと便利でしょう defmodule Db do def query( sql ) when sql != "" do { :ok, result } = Ecto.Adapters.SQL.query( Sample.Repo, sql, [] ) result end def columns( %{ columns: columns } = _result ), do: columns def rows( %{ rows: rows } = _result ), do: rows def columns_rows( result ) do result |> rows |> Enum.map( &( MapList.zip( columns( result ), &1 ) ) ) end def viewable( value ) when is_tuple( value ), do: Timex.to_datetime( value ) def viewable( value ), do: value end lib/util/db.ex Smallexを使うと、リスト同士を結合してマップとして 構成し直す、といったような処理が簡単に書ける

Slide 89

Slide 89 text

88 4-②.SQLを直接実行する:例① 簡単なSQL+Web程度なら、MVC無しでの構築もできます (以下は、ミニモジュール経由でSQLを実行する例です) <%= form_tag( "/", method: :post ) %> <%= @sql %>
<% records = Db.query( @sql ) %> <%= for column <- Db.columns( records ) do %> <%= column %> <% end %> <%= for record <- Db.columns_rows( records ) do %> <%= for column <- Db.columns( records ) do %> <%= record[ column ] |> Db.viewable %> <% end %> <% end %> lib/sample_web/templates/page/index.html.eex

Slide 90

Slide 90 text

89 4-②.SQLを直接実行する:例① 前ページのコードだけで、以下のようなSQLクエリーテストツールが 動く位、カンタンなので、数分でWeb+DBアプリが開発できます

Slide 91

Slide 91 text

90 4-②.SQLを直接実行する:例② DBデータの展開が簡単なので、GoogleChart/jQueryとの 組み合わせで、こんなUIのアプリも気軽にサクッと開発できます (しかも、各データの表示も、毎度DB読込しているのに爆速)

Slide 92

Slide 92 text

91 「え?こんなの気軽にサクッと 作れる訳ないっしょ…」

Slide 93

Slide 93 text

92 と思いませんでしたか?

Slide 94

Slide 94 text

93 他の言語なら、 そうかも知れません…

Slide 95

Slide 95 text

94 しかし、

Slide 96

Slide 96 text

95 Elixir+Phoenixなら 本当に簡単なんです!!

Slide 97

Slide 97 text

96 4-②.SQLを直接実行する:例② ロジック側でSQLを書き、リストマップとして結果を持つようにして、 ページ側からロジックを呼び出し、forループで出力するだけです MVCでこれをやろうとすると、モデルとコントローラの生成や修正も 必要で面倒ですが、SQL直接実行だと気軽にサクっと作れます (DB更新アプリケーションなら、MVC生成の方がラクですが、その 際も、これを併用することは可能です。生成されたDBアクセッサ も、コントローラ内だと煩雑なのでロジック内に書くとスマートです) コード例 (会場以外には、別途 お見せする機会設けます)

Slide 98

Slide 98 text

97 4-②.SQLを直接実行する:例② 開発工数は、20MD程度で、うち、「デザイン作成+CSS開発」 で2/3を占めており、ロジックは、FW開発含め7MDくらい(^_^)

Slide 99

Slide 99 text

98 4-②.SQLを直接実行する:例③ DB操作に加え、外部API呼出との組み合わせで、Backlogや Zendeskなどから情報を取得し、各チケットに紐づく付加情報を 別管理するアプリケーションも数時間でサクっと開発できました (初期バージョンは、1時間で完成しました) Backlog/ZendeskのAPI呼出ライブラリはありますが、簡単 だったので自作しました (API呼出については、次の章で解説) ページネートは、「scrivener」というライブラリで実現しています https://github.com/drewolson/scrivener デモ画面 (スミマセン、会場でしか お見せできない画面です)

Slide 100

Slide 100 text

99 ここまでで、なんとなく Elixir+Phoenixで サクっとアプリ開発できる 雰囲気、感じました?

Slide 101

Slide 101 text

100 4-②.マスタデータ/非リアルタイムデータの扱い マスタデータ/非リアルタイムデータは、頻繁な更新が無い限り、 DBから毎回ロード不要なので、オンメモリ化 (と定期的なバッチ によるロード運用) により、性能向上が見込めます Elixirでオンメモリ化するには、以下3種類の方法があります ① プロセス (GenServer、Agent) のデータとして持たせる ② ETSやmnesia等、Elixir標準のオンメモリDBにロード ③ Redis等のElixir標準で無いオンメモリDBにロード このうち、最もてっとり早いのは、②のETSやmnesia等のElixir 標準のオンメモリDBを使う方法です ※なお、定期的なバッチによるロードは、後の章で解説します

Slide 102

Slide 102 text

101 4-②.マスタデータ/非リアルタイムデータの扱い ETSは、通常のSQLで「DDL」「DML」を扱うのと同じ感覚で、 オンメモリDBを操作できます 詳細は、以下をご覧ください https://qiita.com/rei-m/items/e48ab2cf425e0c94a548 ※オンメモリのETSに対し、同じ操作でファイル永続化できる「DETS」という実装もあります なお、ETS/DETSは、2GByte超のデータは扱えず、複数クラ スタ間で共有もできないため、巨大データもしくは複数クラスタの 共有オンメモリDBを使いたい場合は、mnesiaを使います 詳細は、以下をご覧ください https://qiita.com/k1complete/items/18dba4b8cf0da5952e59 ※いずれもオートスケール不可→要オートスケール化ならRedis

Slide 103

Slide 103 text

102 さきほどのアプリもデータ をETSにロードすれば…

Slide 104

Slide 104 text

103 もっと爆速! (このベンチは次回以降のfukuoka.exにて)

Slide 105

Slide 105 text

104 4-③.外部API呼出、暗号化

Slide 106

Slide 106 text

105 4-③.外部API呼出 外部API呼出は、「HTTPoison」で行い、取得したJSONは、 「Poison」でパースします https://github.com/edgurgel/httpoison https://github.com/devinus/poison これらElixirライブラリと、パターンマッチ、リスト操作にて、いかなる プログラミング言語よりも気軽でパワフルな、APIパーサを作ること ができます

Slide 107

Slide 107 text

106 5.JSONパースに必要なライブラリ導入 JSONパーサアプリを書くにあたり、ElixirのHTTPclientである 「HTTPoison」と、JSONparserである「Poison」を導入します まず、mix.exsに下記赤囲み部分を追加してください 次に、以下コマンドで各モジュールを取得します (要ネット接続) defmodule Crawl.Mixfile do … defp deps do [ { :httpoison, "~> 0.7.2" }, { :poison, "~> 1.5" } ] end end # mix deps.get 再掲: Elixir入門#1より

Slide 108

Slide 108 text

107 lib/Crawl.exを作り、HTTPoisonでQiita APIの呼び出しを 行うコードを書きます 実行すると、Qiitaから取得したJSONが出力されます 前ページで見たBody部だけで無く、StatusCode等も見れます defmodule Crawl do def get() do HTTPoison.get!( "https://qiita.com/api/v2/items?query=Elixir" ) end end # iex –S mix iex> Crawl.get %HTTPoison.Response{body: "[{¥"rendered_body¥":¥"¥¥n¥¥u003ch2¥¥u003e¥¥n … ,¥"title¥":¥"AWS EC2にElixir/Phoenixをインストール¥",¥"updated_at¥":¥"2017-02-10T13:08:41+09:00¥", …(他記事が複数並ぶ)… ¥"twitter_screen_name¥":null,¥"website_url¥":null}}]", …(Body部以外のHeader等が複数並ぶ)… {"Content-Length", "4293"}, {"Connection", "keep-alive"}], status_code: 200} 5.JSONパースに必要なライブラリ導入 再掲: Elixir入門#1より

Slide 109

Slide 109 text

108 記事タイトルをパターンマッチで抽出するコードを追加します 書かれたコードを見直すと、JSON取得→Body抽出→JSON デコード→title抽出と、とても直感的で分かりやすいコードです たった9行のコードで、「Qiita APIを呼び、記事タイトルをリスト アップするアプリ」が書けました 7.JSONパースアプリを仕上げる defmodule Crawl do def get() do HTTPoison.get!( "https://qiita.com/api/v2/items?query=Elixir" ) |> body |> Poison.decode! |> Enum.map( fn( %{ "title" => title } ) -> title end ) end def body( %{ status_code: 200, body: json_body } ), do: json_body end 再掲: Elixir入門#1より

Slide 110

Slide 110 text

109 Elixirなら、外部API呼出と、取得JSONをパースするコードが、 シンプルにまとまる感触が伝わったでしょうか? SmallexのJsonモジュールを使うと、更にシンプルに書けます 4-③.SmallexのJsonモジュール defmodule Crawl do def get() do Json.get( "https://qiita.com", "/api/v2/items?query=Elixir", [], Enum.map( fn( %{ "title" => title } ) -> title end ) end end

Slide 111

Slide 111 text

110 認証を伴うAPIは、APIキー/シークレットと、タイムスタンプ、 HTTPメソッド、パス、ボディを連結し、HMAC SHA-256などで 署名したものをヘッダーに付与して、API呼出を行います 4-③.暗号化 defmodule BitFlyex do defp domain(), do: "https://api.bitflyer.jp" defp api_key(), do: Application.get_env( :bitflyex, :setting ) |> Poison.decode! |> Map.get( "api_key" ) defp secret(), do: Application.get_env( :bitflyex, :setting ) |> Poison.decode! |> Map.get( "secret" ) defp get_private( path, map_function ¥¥ &nop/1 ) do Json.get( domain(), path, [ "ACCESS-KEY": "#{api_key()}", "ACCESS-TIMESTAMP": "#{timestamp()}", "ACCESS-SIGN": "#{sign( "GET", path )}", "Content-type": "application/json", ], map_function ) end def timestamp(), do: Dt.now_timestamp( "-", "T", ":", "." ) |> String.slice( 0, 22 ) defp sign( method, path, body ¥¥ "" ) do :crypto.hmac( :sha256, secret(), timestamp() <> method <> path <> body ) |> Base.encode16 |> String.downcase end …

Slide 112

Slide 112 text

111 DBと外部APIを 操作可能になったので 現代のWeb開発が 大抵可能となった(^o^)

Slide 113

Slide 113 text

112 あとは、バッチとAPI サーバが開発できれば SI開発の表面的な部分 はクリアできるでしょう

Slide 114

Slide 114 text

113 4-④.バッチ

Slide 115

Slide 115 text

114 4-④.バッチ cronライクなバッチを「Quantum」で気軽に作れます https://github.com/c-rack/quantum-elixir インストールは以下の通りです 以下コマンドで各モジュールを取得します (要ネット接続) defmodule Crawl.Mixfile do … defp deps do [ { :quantum, "~> 2.2" }, ] end end # mix deps.get

Slide 116

Slide 116 text

115 4-④.バッチ cronと似たフォーマットで起動時刻設定が行え、cronだとシェル やコマンドを指定する部分は、「モジュールの関数」を指定します 上記バッチを実行開始するには、worker()として追加します config/config.exs … config :account_all_batch, Sample.Scheduler, jobs: [ { "*/10 * * * *" , { BatchDataMart, :update, [ "login" ] } } ] … lib/sample/application.ex defmodule Sample.Application do … def start(_type, _args) do … children = [ … worker( Sample.Scheduler, [] ), ] …

Slide 117

Slide 117 text

116 4-④.バッチ さきほどのアプリも、「データ量が多く重い」や「事前集計が複雑」 などで遅くなる部分は、10分毎バッチで、データマートへの出力を 行うことにより、UIを高速化しました (≒リアルタイム性は捨てた) 1億レコードあるデータをそのままselectすると20秒位ページ 表示にかかるため、抽出用selectをバッチで日次実行した 結果をデータマートに出力し表示 (結果、2秒以内に短縮)

Slide 118

Slide 118 text

117 4-⑤.APIサーバアプリケーション開発

Slide 119

Slide 119 text

118 4-⑤.APIサーバアプリケーション開発 ElixirでAPIサーバアプリケーション開発する場合、以下2種類の 選択肢があります ① PhoenixのJSON API機能を使う ② RubyのREST APIフレームワーク「grape」に影響された ライブラリ「Maru」を使う Webアプリケーションを作るのと、同じ要領でAPIが作れる点で ①のPhoenixがオススメです

Slide 120

Slide 120 text

119 5.JSON APIを作ってみる JSON APIも、前述したWebアプリとほぼ同じ手順で作れます まずJSON API用のPhoenixプロジェクトを作成します モデルを格納するDBを作成します JSON API用のモデル生成を行います (違いはjson指定のみ) 前述のWeb用のモデルと全く同じモデルで作ってみます # mix phx.new api --no-brunch # cd api # mix phx.gen.json Tool Post posts title:string body:text … Add the resource to your api scope in lib/api_web/router.ex: resources "/posts", PostController, except: [:new, :edit] Remember to update your repository by running migrations: $ mix ecto.migrate # mix ecto.create 再掲: Elixir入門#3より

Slide 121

Slide 121 text

120 5.JSON APIを作ってみる web/router.exへのパス追加を行います 同時に、CSRFを防止する部分も解除しておきます モデルのマイグレーションを行います # mix ecto.migrate defmodule ApiWeb.Router do use ApiWeb, :router pipeline :browser do … plug :fetch_flash # plug :protect_from_forgery plug :put_secure_browser_headers … scope "/", ApiWeb do pipe_through :browser # Use the default browser stack get "/", PageController, :index resources "/posts", PostController, except: [:new, :edit] end … end CSRF(cross-site request forgeries)の防止 が行われると、CSRFトークン(csrf_token)を渡さ ないとアクセスできなくなるため解除する ※ステートレスなREST APIでの本CSRF対策は実装が難しい 再掲: Elixir入門#3より

Slide 122

Slide 122 text

121 5.JSON APIを作ってみる マイグレーションの結果、テーブル追加されるので、確認します # sudo -u postgres psql psql (9.3.18) Type "help" for help. postgres=# ¥c api_dev You are now connected to database “api_dev" as user "postgres". web_dev=# ¥d posts Table "public.posts" Column | Type | Modifiers -------------+-----------------------------+---------------------------------------------------- id | integer | not null default nextval('posts_id_seq'::regclass) title | character varying(255) | body | text | inserted_at | timestamp without time zone | not null updated_at | timestamp without time zone | not null Indexes: "posts_pkey" PRIMARY KEY, btree (id) 再掲: Elixir入門#3より

Slide 123

Slide 123 text

122 5.JSON APIを作ってみる JSON API用のコマンドとして、どのようなものが用意されたかは、 以下で確認できます 一覧取得 (index)は、/postsへのGETで行います アイテム登録 (create)は、/postsへのPOSTで行います 各アイテム取得 (show)は、/posts/1、/posts/2等のID指 定でのGETで取得でき、アイテム更新 (update)はID指定の PUTもしくはPATCH、アイテム削除 (delete)はID指定での DELETEで行います # mix phx.routes page_path GET / Api.PageController :index post_path GET /posts Api.PostController :index post_path GET /posts/:id Api.PostController :show post_path POST /posts Api.PostController :create post_path PATCH /posts/:id Api.PostController :update PUT /posts/:id Api.PostController :update post_path DELETE /posts/:id Api.PostController :delete 再掲: Elixir入門#3より

Slide 124

Slide 124 text

123 5.JSON APIを作ってみる Phoenixサーバを起動します JSONクライアントで「http://localhost:4000/posts」をGET リクエストすると、アイテムが空のJSONが返ってきます # iex -S mix phx.server Google ウェブストアで Postmanをインストー ルしてください 再掲: Elixir入門#3より

Slide 125

Slide 125 text

124 5.JSON APIを作ってみる 「http://localhost:4000/posts」へのPOSTリクエストにて titleとbodyを下記JSONのように指定すると、新たなアイテムを 追加できます 再掲: Elixir入門#3より

Slide 126

Slide 126 text

125 残るは、例外処理と 監視/ログ

Slide 127

Slide 127 text

126 4-⑥.監視/ログ/耐障害性

Slide 128

Slide 128 text

127 従来のプログラム 4-⑦.try…catchからどう変わるのか? try…catchによる例外処理は、「本体処理」をtry~で囲み、 例外発生時は、各catchで捕まえ、例外ハンドラを起動します 一方、Elixirでは、本体処理には手を加えず、「スーパーバイザ」 と呼ばれる監視プログラムを別系で配備します try 本体処理 例外ハンドラ群 catch① 例外ハンドラ① catch② 例外ハンドラ② Elixirプログラム 本体処理 スーパーバイザ (プロセス監視) 復旧戦略 ダウン 監視 ダウンしたら 再起動 再掲: Elixir入門#6より

Slide 129

Slide 129 text

128 4-⑦.try…catchからどう変わるのか? 監視プログラムからの復旧戦略の代表として「プロセス再起動」が ありますが、プロセス起動が軽量なElixirだから実現が現実的に なるという、プログラミング言語の特性が大きく寄与しています (関数型言語のイミュータブルな特性も、この実現に貢献します) ・本体処理と例外処理を1つ のコードにまとめられる ※これは分離できない、という デメリットでもある メリット デメリット Elixir 耐障害性 例外処理 ・メモリリークを作り込みやすい ・不整合を作り込みやすい ・プロセスを再起動する設計が 考慮から漏れる可能性がある ・プロセス再起動で全てが解決 できるとは限らない ※とはいえ、プロセス再起動の 設計は例外処理でも本当 は必要 ・障害対応を本体処理から 分離できる ・メモリリークや不整合を解消 できる構造 ・プロセス再起動を予め設計 再掲: Elixir入門#6より

Slide 130

Slide 130 text

129 4-⑦.スーパーバイザのプロセス監視、復旧 スーパーバイザのコードは、以下の通りです たった、これだけのコードを追加するだけで、プロセスダウン監視と プロセスダウン後の再起動が実現されることは、驚異的です 例外処理で、同等の処理を書くことは、不可能に限りなく近く、 また自前の監視系を作るのも、骨が折れる作業です Elixirは、この機能が標準装備されており、非常にお手軽です import Supervisor.Spec defmodule PassSupervisor do def start_link() do servers = [ worker( PassGenServer, [ 0, [ name: :server_process ] ] ) ] Supervisor.start_link( servers, strategy: :one_for_one ) end end lib/pass_supervisor.ex 再掲: Elixir入門#6より

Slide 131

Slide 131 text

130 4-⑦.耐障害性のための構成と復旧戦略 更に、本体処理自体が、複数のプロセスで構成される場合は、 サブのスーパーバイザを作り、そのプロセスグループの中で再起動 を制御できます 共通データ 保持プロセス スーパーバイザ 監視 本体処理① プロセス 監視 本体処理②-1 プロセス 監視 本体処理②用 スーパーバイザ 本体処理②-2 プロセス 監視 監視 再掲: Elixir入門#6より

Slide 132

Slide 132 text

131 4-⑦.耐障害性のための構成と復旧戦略 スーパーバイザから、スーパーバイザを起動するコードは、以下の ようになります 通常のサーバを起動するコードと、ほぼ変わりません import Supervisor.Spec defmodule PassSubSupervisor do def start_link() do servers = [ worker( PassGenServer, [ 0, [ name: :server_process ] ] ) ] Supervisor.start_link( servers, strategy: :one_for_one ) end end lib/pass_sub_supervisor.ex import Supervisor.Spec defmodule PassSupervisor do def start_link() do servers = [ supervisor( PassSubSupervisor, [ 0, [ name: :ssv_process ] ] ) ] Supervisor.start_link( servers, strategy: :one_for_one ) end end lib/pass_supervisor.ex 再掲: Elixir入門#6より

Slide 133

Slide 133 text

132 4-⑦.耐障害性のための構成と復旧戦略 「復旧戦略」が、何種類か選べます (代表2つを紹介) ⚫ one_for_one ・・・ 1プロセス落ちたら1プロセス再起動 ⚫ one_for_all ・・・ 1プロセス落ちたら配下を全再起動 共通データ 保持プロセス スーパーバイザ 監視 本体処理① プロセス 監視 本体処理②-1 プロセス 監視 本体処理②用 スーパーバイザ 本体処理②-2 プロセス 監視 監視 再掲: Elixir入門#6より

Slide 134

Slide 134 text

133 4-⑦.Dynamic Supervisor Elixir 1.6から、「Dynamic Supervisor」という、Elixir独自 の新たなスーパーバイザが追加されました 通常のスーパーバイザは、監視対象のプロセスをスーパーバイザ の起動前に指定する必要ありますが、Dynamic Supervisor では、動的に監視対象プロセスを指定できます 詳細は、以下をご覧ください https://qiita.com/melpon/items/853a5bc2ff4279a5dfea

Slide 135

Slide 135 text

134 4-⑦.ログ出力 ログ出力は、Elixirライブラリの「LoggerFileBackend」を導入 すれば、とても簡単に実現できます https://github.com/onkel-dirtus/logger_file_backend 詳細は、以下をご覧ください https://qiita.com/letusfly85/items/cd341d7a61619782183d

Slide 136

Slide 136 text

135 4-⑦.Visualixirでプロセスの可視化 Visualixirは、Elixirのプロセスを可視化するツールです https://github.com/koudelka/visualixir 顕微鏡で見る微生物のような不思議なUIで可視化されます 再掲: Elixir入門#5より

Slide 137

Slide 137 text

136 4-⑦.Elixirの素晴らしい測定ツール群 「WobServer」は、手軽にElixirやErlangVMの内部動作を 確認したり、デバッグできるツールです

Slide 138

Slide 138 text

137 4-⑦.Elixirの素晴らしい測定ツール群 「ERLANG.PL」は、監視ツールという領域を超えるような美しい ビジュアルを持つ、ErlangVMのパフォーマンス分析ツールです

Slide 139

Slide 139 text

138 ここからは Elixirならではの 強み2つをプッシュ

Slide 140

Slide 140 text

139 4-⑦.マルチコア活用

Slide 141

Slide 141 text

140 4-⑦.マルチコアを使いこなすのは難しい? 以上の通り、マルチコア活用のためには、プログラミングテクニックで カバーし切れない課題が多くあるため、プログラミング言語やライブ ラリによるサポートの充実度合いが大事になってきます Elixirは、①~③が言語・ライブラリの両面でサポートされており、 かつ非常に簡単に使えるため、これら課題を楽々とクリアできます ①マルチコア向けの処理分割が必要 ⚫ 「Flow」と「GenStage」にて、並列化と処理分割を実現 ②同時メモリーアクセスすると性能劣化の懸念 ⚫ 関数型言語のため、メモリーは最初から全てimmutable ③マルチスレッドの扱いが難しい ⚫ 「軽量プロセス」と「アクターモデル」で、負荷無く、カンタン 再掲: Elixir入門#8より

Slide 142

Slide 142 text

141 4-⑦.Flow…マルチコア最終兵器 Flowによるデータ処理の並列化は、Enumから、赤丸部分のみ 修正を行うだけで、非常にカンタンです defmodule ElixirFlow do def run( filename ) do filename |> File.stream! # データクレンジング |> Flow.from_enumerable() |> Flow.map( &( String.replace( &1, ",", "¥t" ) ) ) # ①CSV→TSV |> Flow.map( &( String.replace( &1, "¥r¥n", "¥n" ) ) ) # ②CRLF→LF |> Flow.map( &( String.replace( &1, "¥"", "" ) ) ) # ③ダブルクォート外し # 集計 |> Flow.map( &( &1 |> String.split( "¥t" ) ) ) # ④タブで分割 |> Flow.map( fn [ _head | tail ] -> tail |> List.first end ) # ⑤2番目の項目を抽出 |> Flow.partition |> Flow.reduce( fn -> %{} end, fn( name, acc ) # ⑥同値の出現数を集計 -> Map.update( acc, name, 1, &( &1 + 1 ) ) end ) |> Enum.sort( &( elem( &1, 1 ) > elem( &2, 1 ) ) ) # ⑦多い順でソート end end lib/elixir_flow.ex 再掲: Elixir入門#8より

Slide 143

Slide 143 text

142 4-⑦.Flow…マルチコア最終兵器 実行します Flowでは、30万行の処理に、2.53秒と、Enumの6倍の性能 が出ました このようなカンタンな修正だけで、性能が数倍も改善されるFlow は、凄まじい機能だと思いませんか? # iex -S mix iex> ElixirFlow.run( "test_300000.csv" ) 2017-12-22 06:58:23.907000Z 2017-12-22 06:58:26.438000Z 0m2.531s [{"Muckenfuss", 13}, {"Lieurance", 13}, {"Linkovich", 13}, {"Shultis", 12}, {"Coppes", 12}, {"Gargis", 12}, {"Macey", 12}, {"Musa", 12}, {"Cefaratti", 12}, {"Brabston", 12}, {"Razor", 12}, {"Susmilch", 12}, {"Sockalosky", 12}, … 再掲: Elixir入門#8より

Slide 144

Slide 144 text

143 4-⑦.Flow…マルチコア最終兵器 EnumとFlowのマルチコアCPU利用を見比べてみると、Flowが 全マルチコアをフル活用し、処理を短時間で完了させていること が分かります ■Enum ■Flow 再掲: Elixir入門#8より

Slide 145

Slide 145 text

144 4-⑧.AI・ML呼出&データサイエンス

Slide 146

Slide 146 text

145 4-⑧.ElixirからKerasを呼び出す Kerasを使うPythonも当然呼び出せます ファイル保存したら、以下コマンドを実行します defmodule Pyex do def predict() do { :ok, py_exec } = :python.start( [ python_path: 'lib' ] ) :python.call( py_exec, :predict_sin, :predict, [] ) end end # iex –S mix iex> Pyex.predict lib/pyex.ex 再掲: Elixir入門#7より

Slide 147

Slide 147 text

146 4-⑧.ElixirからKerasを呼び出す Python単独と同様、sin波の予測が行われます 再掲: Elixir入門#7より

Slide 148

Slide 148 text

147 4-⑧.実際のElixirコード例 注目していただきたいのは、Elixirにおけるデータ処理が、とても 簡単に記載できる点です 「データクレンジング」と「集計・統合」の本体処理は、Elixirだと 以下の通り、非常にシンプルで、直観的です # データクレンジング |> Flow.from_enumerable() |> Flow.map( &( String.replace( &1, ",", "¥t" ) ) ) # ①CSV→TSV |> Flow.map( &( String.replace( &1, "¥r¥n", "¥n" ) ) ) # ②CRLF→LF |> Flow.map( &( String.replace( &1, "¥"", "" ) ) ) # ③ダブルクォート外し # 集計・統合 |> Flow.map( &( &1 |> String.split( "¥t" ) ) ) # ④タブで分割 |> Flow.map( fn [ _head | tail ] -> tail |> List.first end ) # ⑤2番目の項目を抽出 |> Flow.partition |> Flow.reduce( fn -> %{} end, fn( name, acc ) # ⑥同値の出現数を集計 -> Map.update( acc, name, 1, &( &1 + 1 ) ) end ) |> Enum.sort( &( elem( &1, 1 ) > elem( &2, 1 ) ) ) # ⑦多い順でソート 再掲: Elixir入門#9より

Slide 149

Slide 149 text

148 4-⑧.実際のElixirコード例 一方、Javaのコードは、可読性がElixirと比べ、良くは無いため、 処理が小さいうちはメンテナンスできたとしても、複雑になるほど、 保守コストが跳ね上がっていくことが予想できます // データクレンジング // ①CSV→TSV String[] lines1 = new String[ lines0.length ]; for ( i = 0; i < lines0.length; i++ ) lines1[ i ] = lines0[ i ].replace( ",", "¥t" ); // ②CRLF→LF String[] lines2 = new String[ lines1.length ]; for ( i = 0; i < lines1.length; i++ ) lines2[ i ] = lines1[ i ].replace( "¥r¥n", "¥n" ); // ③ダブルクォート外し String[] lines3 = new String[ lines2.length ]; for ( i = 0; i < lines2.length; i++ ) lines3[ i ] = lines2[ i ].replace( "¥"", "" ); // 集計 // ④タブで分割 String[][] lines4 = new String[ lines3.length ][]; for ( i = 0; i < lines3.length; i++ ) lines4[ i ] = lines3[ i ].split( "¥t" ); … 1ページ目 再掲: Elixir入門#9より

Slide 150

Slide 150 text

149 4-⑧.実際のElixirコード例 // ⑤2番目の項目を抽出 String[] lines5 = new String[ lines4.length ]; for ( i = 0; i < lines4.length; i++ ) lines5[ i ] = lines4[ i ][ 1 ]; // ⑥同値の出現数を集計 LinkedHashMap< String, Integer > lines6 = new LinkedHashMap< String, Integer >(); for ( String line : lines5 ) { if ( lines6.containsKey( line ) ) { lines6.put( line, lines6.get( line ) + 1 ); } else { lines6.put( line, 1 ); } } // ⑦多い順でソート List< Entry< String, Integer > > lines7 = new ArrayList< Entry< String, Integer > >( lines6.entrySet() ); Collections.sort( lines7, new Comparator< Entry< String, Integer > >() { public int compare( Entry< String, Integer > item1, Entry< String, Integer > item2 ) { return item2.getValue().compareTo( item1.getValue() ); } } ); 2ページ目 再掲: Elixir入門#9より

Slide 151

Slide 151 text

150 4-⑧.実際のElixirコード例 これは、Goにおいても似たような状況です // データクレンジング // ①CSV→TSV var lines1 []string for i := 0; i < len( lines0 ); i++ { lines1 = append( lines1, strings.Replace( lines0[ i ], ",", "¥t", -1 ) ) } // ②CRLF→LF var lines2 []string for i := 0; i < len( lines1 ); i++ { lines2 = append( lines2, strings.Replace( lines1[ i ], "¥r¥n", "¥n", -1 ) ) } // ③ダブルクォート外し var lines3 []string for i := 0; i < len( lines2 ); i++ { lines3 = append( lines3, strings.Replace( lines2[ i ], "¥"", "", -1 ) ) } // 集計 // ④タブで分割 var lines4 [][]string for i := 0; i < len( lines3 ); i++ { lines4 = append( lines4, strings.Split( lines3[ i ], "¥t" ) ) } 1ページ目 再掲: Elixir入門#9より

Slide 152

Slide 152 text

151 4-⑧.実際のElixirコード例 // ⑤2番目の項目を抽出 var lines5 []string for i := 0; i < len( lines4 ); i++ { lines5 = append( lines5, lines4[ i ][ 1 ] ) } // ⑥同値の出現数を集計 lines6 := Agreegates{} var rejected = lines5 for { if len( rejected ) <= 0 { break } match := rejected[ 0 ] fn := func( item string, match string ) bool { return item == match } var count int count, rejected = reject( fn, rejected, match ) var family_count = Agreegate{ family: match, count: count } lines6 = append( lines6, family_count ) } // ⑦多い順でソート sort.Sort( Desc{ lines6 } ) } func reject( fn func( item string, match string ) bool, list []string, match string ) ( int, []string ) { count := make( []string, 0 ) rejected := make( []string, 0 ) for _, item := range list { if fn( item, match ) == true { count = append( count, item ) } else { rejected = append( rejected, item ) } } return len( count ), rejected } 2ページ目 再掲: Elixir入門#9より

Slide 153

Slide 153 text

152 4-⑧.実際のElixirコード例 Elixirならではのデータ処理に、もう一歩、踏み込んでみましょう たとえば、RDBのような、比較的データがキレイなもの以外に、 ログファイルのような「非定型データ」から、何らかのデータを抽出 して活用したい、というケースは、割と多いのでは無いと思います 実際に、ログから抽出するケースについて見ていきましょう [datetime] 2017-09-14 03:46:03.931377, [subtype] bot_message, [username] segment_generate@PBAT-16, [pretext] [critical] failed to generate segment at 2017-09-14 03:45:56 UTC, [fields] <> [id: 108] 株式会社hogehoge <> [id: 6959] 【mail】point <> PG::UndefinedTable: ERROR: relation customers_bd_wyna8r_1 does not exist : insert into segments_bd_wyna8r_1__20170914034556(segment_id, visitor_id) select 6959, visitor_id from ( select visitors.visitor_id from visitors_bd_wyna8r_1 visitors inner join customers_bd_wyna8r_1 customers on visitors.unique_visitor_id = customers.unique_visitor_id inner join ( select unique_visitor_id, max(id) as max_id from customers_bd_wyna8r_1 where unique_visitor_id is not null and unique_visitor_id <> group by unique_visitor_id ) tmp_customers on customers.id = tmp_customers.max_id and customers.unique_visitor_id = tmp_customers.unique_visitor_id inner join ( select unique_visitor_id, max(first_visit_date) as max_first_visit_date from visitors_bd_wyna8r_1 where unique_visitor_id is not null and unique_visitor_id <> group by unique_visitor_id ) tmp_visitors on visitors.first_visit_date = tmp_visitors.max_first_visit_date and visitors.unique_visitor_id = tmp_visitors.unique_visitor_id where customers.customer_id in (select x_4608.c_148046 as customer_id from x_4608 where x_4608.c_148046 not in (select x_4608.c_148046 as customer_id from x_4608 where x_4608.c_148074 like %1% group by x_4608.c_148046) group by x_4608.c_148046 intersect select x_4608.c_148046 as customer_id from x_4608 group by x_4608.c_148046 having sum(case when 1 = 1 then x_4608.c_148069 else 0 end) > 299 intersect select x_4608.c_148046 as customer_id from x_4608 where cast(x_4608.c_148065 as BIGINT) <= 1497657599000 group by x_4608.c_148046) group by visitors.visitor_id ) _tmp , [channel_id] C2T611ZP1, [channel_name] 再掲: Elixir入門#9より

Slide 154

Slide 154 text

153 4-⑧.実際のElixirコード例 以下Elixirコードは、特定の文字列プリフィックスを持つ行のみを まず拾い上げ、更にその行中に、特定の取得したいデータを持つ ような場合は抽出し、mapにして返す例です Regex.named_captures()だと、ログのような非定型データ でも、パターンマッチでカンタンに値を拾い出すことができます "some.log" |> File.stream! |> Stream.filter( &( String.contains?( &1, "[pretext] [critical] failed to generate segment" ) ) ) |> Stream.map( &( Regex.named_captures( ~r/<> ¥[id: (?.*)] (?.*) <> ¥[id: (?.*)] (?.*) <>/, &1 ) ) ) |> Stream.map( fn( %{ "accNo" => accNo, "accName" => accName, "segNo" => segNo, "segName" => segName } ) -> "#{accNo},#{accName},#{segNo},#{segName}¥n" end ) |> Enum.to_list 再掲: Elixir入門#9より

Slide 155

Slide 155 text

154 Elixirのシンプルさ とパワーを感じて いただけましたか?

Slide 156

Slide 156 text

155 5.この1年、福岡で爆誕するElixirムーブメント

Slide 157

Slide 157 text

156 5.この1年、福岡で爆誕するElixirムーブメント 現時点における、ElixirおよびElixirの周辺状況が、見えてきた のでは無いでしょうか? いま、Elixirに足りないものは、「ユーザの数」だけであり、プログラ ミングやコンピューティングでの不足は、他言語と比べても無い… どころか、他言語にはマネできない多くのアドバンテージがあります 福岡という地で、最先端のIT・SIを実現するにあたり、Elixirは、 最も有力なフロンティアです これを、「チャンス」と見るか、「ブームになるか分からない不確定 要素」と見るかは、個々人によると思いますが、fukuoka.exは、 今年が「Elixirに火がつく元年」と捉え、構想しています そのホンの一部をご紹介して、終わりにしましょう

Slide 158

Slide 158 text

157 5.この1年、福岡で爆誕するElixirムーブメント fukuoka.ex、取材受けます(インタビュー掲載) 福岡でのElixir 大型案件始動 福岡でブームに&Elixirを求めて移住してくる第1号が確定w 高島市長と会見 感謝状…届くか? 福岡でのElixirプロダクション 採用事例が100件突破 300人規模のElixir イベントを福岡で開催 季節外れのAdvent Calendar でQiita Elixirカテゴリを4~6月 ジャック (新人や転職組を狙う) Elixir Advent Calendarの 本家を福岡勢で完全制圧する fukuoka.exを100人 規模で開催 @ LINE ElixirでDjango以上に お手軽でWIX並に洗練 されたモダンUI生成する エンジンと、それで作った Elixirポータルをリリース fukuoka.ex、2回目の取材 来年の展望・野望を語る 高島市長を 登壇に呼ぶ 野心を振り返る 忘年会バージョン & fukuoka.ex 世界へ打って出る Elixir移住者 インタビュー ZEAM α版リリース? (Elixir Conf間に合うかな?) fukuoka.exによる Elixir本を出版 &出版記念パーティ Udemy Elixir 講座リリース 世界レベルのElixir オープンソースをリリース

Slide 159

Slide 159 text

158 「fukuoka.ex祭り」 最初の派手な1年 あなたも join!!

Slide 160

Slide 160 text

159 ご清聴ありがとうございます