Gunosy Tech Blog

Gunosyの開発メンバーが知見を共有するブログです。

Blockchain.tokyoにてSolidityの話をしました

こんにちは、Gunosyで新規事業担当兼CTOの松本(@y_matsuwitter)です。 先日、弊社にてblockchain.tokyo#2を開催しましたが、まとめ記事はAnypayさんの方で書いていただいたようですので、本イベントでトークさせていただいたSolidity with Test&CIについて簡易にこちらにも共有させていただこうかとおもいます。

medium.com

本トークでは、Ethereumの詳細面よりも、実際にEthereumに興味をもったデベロッパーの皆さんが簡単に開発環境を構築してコードを書き始めてもらうことを主眼に用意したものなので、Truffleによるテストをすでに進めているという方には物足りないかもしれません。

スライドはこちら。

Ethereum、EVM、そしてSolidity

今回の勉強会では個人的に調査・開発しているEthereum、およびその上でのアプリケーション実行環境であるEVM、そこでの実行コードを記述できるSolidityとその基本的な開発フローについて解説させていただきました。

Ethereumについては、その開発規模や流通している時価総額もあってか多くの解説も出ており、またご存じの方も多いかと思います。 簡単にいえばEthereumとは「中央のいない分散型のアプリケーション(Dapps)の実行環境」ということが出来、World Computerを志向したブロックチェーンと言えます。

youtu.be

自分はEC2とS3に始まるクラウドコンピューティングやマネージド・サービスの登場から昨今のServerlessという流れを踏まえた上で、こうした分散実行環境は将来的に次のアーキテクチャの一部として認識しても良いものかと思い注目しています。

さて、どなたでもEthereumの上でアプリケーションを開発できるわけですが、そのアプリケーションはどういった構造で動作しているのでしょうか。スライドでも説明させていただきましたが、Ethereumのアプリケーションは、コントラクトと呼ばれる実行コードが登録されたアドレスに対して所定のパラメタを付与したトランザクションを発行することで、登録された機能を実行する形式になっております。 この実行環境のことをEVM (Ethereum Virtual Machine)といい、その実行コードをEVM Codeと呼びます。EVM Codeはスタック言語と呼ばれるBitcoinのScriptと同種の低級言語をbytecodeで記録したもので、Bitcoinとの違いはチューリング完全である点です。 実行に際しては、EVM Codeに定義されているOpcodesと呼ばれる各種命令のスタックをEVMが解釈し実行するのですが、この際にEthereum上のトークンとして設計されているEther(ETH)を利用料として徴収します。これをGasと呼び、ETHが通貨ではなく燃料であると呼ばれる所以です。 コントラクトに対してトランザクションを発行すると自身で設定したGas Fee(普段送金手数料として見ている事が多いかもしれません)と呼ばれる手数料に対して、スタック上のOpCodesを一つ実行するごとに命令それぞれで設定されたコスト分をマイナスしていき、0になる、ないしは停止するまで実行していきます。燃料を設定することでブロックチェーン上で悪意のあるコストの高いコードの実行に対して、金銭的な壁を設けているわけですね。

この仕組を踏まえると、コントラクトを実際に自分で作成する際にはEVM Codeを開発する必要があるわけですが、非常に低級な言語であるため現実的でありません。これらに対して現状ではいくつかの高級言語が公開されており、その一つがSolidityというわけです。 SolidityはJavascriptライクな文法で書くことができ、solcコンパイラを通じてEVM Codeを生成することが出来ます。言語の仕様等に興味のある方は公式ドキュメントから入ると良いでしょう。

公式ドキュメント

https://solidity.readthedocs.io/en/develop/

Solidityの言語詳細は今回のブログでは割愛しますが、我々がEthereum上で実行可能なコントラクトを実装し分散アプリケーションを作成するためには、Solidityでコントラクトを記述し、それらをEVM Codeとしてコンパイルし、Ethereum上にデプロイする、という流れを踏まえておけばよいでしょう。

SolidityでtestとCIをするということ

実際にアプリケーションを開発するとなると、皆さん当然TestやCIの情報を調べ始めると思います。 EthereumでのDappを書く際には、普段のコード以上にTestとCIについて考える必要があります。 なぜなら、Ethereumのコントラクトは不変であり一度デプロイすると更新することが出来ません。 それはEthereumがこれまで直面してきたThe DAO事件やParity Multisig Walletの凍結事件のような騒動に発展しています。いずれもコントラクトの実装ミスから数十〜数百億の資金が盗難ないしは凍結されるという被害につながっております。

こうしたミスを未然に防ぐため、コードのベストプラクティスを都度収集・共有する姿勢も重要ですがそれ以上に徹底してテストによる検証を行うことが重要であると考えています。

Truffle 4.0を使おう

こうしたコントラクトのテストコードの記述とCIをサポートするツールはいくつか有りますが、現状ではTruffle 4.0を利用するのが最も取りやすい手段だと考えています。 Truffle

github.com

実際のEthereumのコントラクト実行については、先に述べた通りコントラクトアドレスに対するトランザクションを完了させることで行われるものです。これはつまりテスト的な実行をするにもEthereumのブロックチェーンと接続し、都度トランザクションの送信とそれを実行するマイナー相当のプロセスが必要ということになります。 テスト実行に都度そうしたブロックチェーンの構築とマイニングは、その実行時間的にも非現実的です。 こうした状況に対して、TruffleはEthereumをエミュレートするテストネットワーク機能(TestRPC)を備えており、こちらを利用することで実際にブロックチェーンを用意することなく低コストでテストコードの記述が可能となっています。

実際のテストコードについては、Solidityのコントラクトのデプロイ・実行、そしてその値に対するアサーションをJavascriptにてMochaライクなスタイルで記述していきます。 例を挙げると下記のようなものになります。

var MetaCoin = artifacts.require("MetaCoin");
    
contract('MetaCoin', function(accounts) {
  it("should put 10000 MetaCoin in the first account",
    // asyncを利用
    async function() {

    // deployされたコントラクトを取得
    var d = await MetaCoin.deployed()

    // 残高の取得
    var balance = await instance.getBalance.call(accounts[0])

    assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account");
  })
})

基本的には①Contractの実体をネットワークに作成・ないしはデプロイ済みのものを取得②トランザクションの送信③値の検証と言った流れをPromiseを利用して記述します。 上記ではTruffleをnode 7.6以降で実行しており、async/awaitを用いた記述に書き換えています。

Truffle 4.0以上のバージョンでは、TestRPC機能を内包し、truffleコマンド単体で上記のテストを実行、また実際のネットワークに対するデプロイが可能なためCircleCI等のCIツール上でも1コマンドで検証を実行することが可能です。

実際のテストにおいては、過去リリースされてきた大規模なDappsプロジェクトや広く使われているSolidityフレームワークのテストを読むことが一番勘所をつかみやすいのかなと思いますので、自分が参考にしているリポジトリを最後に紹介しておきます。

OpenZeppelin/zeppelin-solidity github.com

ALISプロジェクト github.com

最後に

Dappsは自分が今後の発展を楽しみにしている技術の一つです。 様々な仲介のあるアプリケーションをより効率的に実装し、公開する手段を新しいアーキテクチャで実現できるものだと思います。 個人開発者でもDappsの開発は比較的容易であり、安全な運用に関してもtruffleといった周辺ツールの充実化とベストプラクティスの集積から可能になってきていると思います。 ぜひ、皆さんもEthereum上でなんらかのDappsを作って公開してみましょう。


Blockchain.tokyoは今後も継続的に開催していく予定です。 特に国内においてBlockchainを技術的トピックとして取り扱うエンジニア向けコミュニティとして大きなものにしていきたいと思っております。興味ある方ぜひぜひ今後もご参加ください。 blockchain-tokyo.connpass.com

また、弊社の新規事業開発室ではブロックチェーンやスマートスピーカー、VR/ARと言った新規領域での研究・開発を進めており、メンバーを募集しております。 www.wantedly.com

www.wantedly.com

Elasticsearch5系で、シャードunassignedによるstatus redを強引に修復する方法

はじめまして、Gunosyでサーバーサイドエンジニアをしているmanoと申します。 最近ハマっていることは、Huluで安室奈美恵さんの特番をみることです。引退するなんて・・・本当に惜しいですね。

私は現在ニュースパスというアプリのサーバーサイド開発を担当しています。
ニュースパスでは、記事検索機能等でElasticsearchを使っています。運用周りではcuratorを使っています。 最近そのあたりでハマってしまったことがあったので、今回はそれについて書こうと思います。

起こったこと

開発環境にて、Elasticsearchのノードインスタンスをシャットダウンしたときに、いくつかのシャードがunassignedになりステータスもredとなってしまうということがありました。
それでも検索機能は生きてはいたのですが、それによりレスポンスタイムが大幅に増加してしまっていました。
下の画像は当時のElasticsearch clientのELB Latencyです。平均値で20秒近くと、通常の200倍程度になっていました。 f:id:jumpeim37:20171110173510p:plain とりあえず応急処置を施すことにしました。
※ニュースパスでは、Elasticsearchからデータがロストしても後から復旧可能なため、こちらの応急処置は「unassignedになっているシャードは、いったんはデータ復旧しなくていい」というときの応急処置です。

現状確認

まずはクラスタのステータスを確認

$ curl -XGET host:9200/_cluster/health

{
  "cluster_name": "クラスタ名",
  "status": "red",
  "timed_out": false,
  "number_of_nodes": 13,
  "number_of_data_nodes": 9,
  "active_primary_shards": 170,
  "active_shards": 340,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 112,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 75.22123893805309
}

うーん、"status": "red"です。そしてunassigned_shardsはあるけどdelayed_unassigned_shardsはないから、この後自助作用で復旧することはなさそう。
次に、実際にunassignedとなっているシャードの情報を取得します。

$ curl -XGET host:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason

index-1   2 p STARTED 
index-1   2 r STARTED 
index-1   3 r UNASSIGNED NODE_LEFT
index-1   3 p UNASSIGNED NODE_LEFT
index-1   1 r STARTED 
index-1   1 p STARTED 
index-1   5 p UNASSIGNED NODE_LEFT 
index-1   5 r UNASSIGNED NODE_LEFT 
index-1   4 p STARTED 
index-1   4 r STARTED 

なるほど・・・index-1のシャード3・5が、primaryもreplicaもないと。
ここでバックアップデータからの復旧などができればそれをすればいいかと思いますが、今回はそういうのもなくて「とにかく犠牲を払ってでも復旧を!」というときの手段を書いていきます。(実行される方は自己責任でお願いします。。)

対処法

概要: 空のプライマリシャードをノードを指定してセットしていく

強引です(笑)

手順1 シャードを入れるノードのnode_idを取得

node_idがわかっているならスキップしても問題ありません。 サーバーIPアドレス等しかわからないとき、下記のように調べていきます。

$ curl -XGET host:9200/_nodes/(nodeサーバーのIPアドレスなど)

設定によっては1サーバー内に複数のノードがあるためです。
(後述のnode.max_local_storage_nodesが2以上で設定されているとき)

手順2 空のプライマリシャードをセットしていく

こちらを参考に、rerouteコマンドにて空のプライマリシャードを突っ込んでいきます。

curl -XPOST 'http://localhost:9200/_cluster/reroute' -d '{
    "commands": [{
        "allocate_empty_primary": {
            "index": "index-1",
            "shard": 3,
            "node": "node_id",
            "accept_data_loss": true
        }
    }]
}'

これで、指定したノードに、指定したindex・shardの空プライマリデータがassignされます。
環境にもよるかとは思いますが数秒でassignされます。 このように欠損してしまった全てのシャードの空データをセットしていけば、unassignedシャードがなくなった時点でstatus greenに復旧します。

そもそも

なおそもそも、このようなシャードの欠損を起こりにくくするには、下記のパラメータを適切に設定すると効果があるかと思います。

  • node.max_local_storage_nodesを1(=デフォルト)にしておく
    本番環境ではまずしないかと思いますが、こちらが2以上になっていると、同一のサーバーインスタンスに同一シャードのprimary・replicaが保存されてしまう可能性があり、その状態でそのインスタンスが落ちるとallocateが正常にできずstatus redになります。
  • delayed_timeoutを設定する
    ノードのネットワークが瞬断したときなどのnode_left発生時、即座にallocateが動いてしまうと過大な負荷がかかってしまうため、allocateが動くまでの時間を遅延させるパラメータです。 (デフォルト: 1分)

最後に

Gunosyではニュースパス等自社サービスのサーバーサイドエンジニアを募集中です!

hrmos.co hrmos.co

Cloudera World Tokyo 2017で発表しました

かとうです。Amazon Echoを買ってみたいのですが、まだ招待メールが届いておりません。

それはさておき、11月7日に行われたCloudera World Tokyo 2017にて登壇する機会をいただきまして、そのご報告です。

イベントについてはこちらをご覧ください。

www.clouderaworldtokyo.com

発表資料はこちらです。

発表内容について

Gunosyの広告技術部では広告リクエスト時にCTRやCVRを返す新たな推定APIを絶賛開発中でして、そのモデルをSparkの機械学習アプリケーションをEMR上で実行し、作成しております。

Cloudera Altus発表当時からどういったものか気になっておりまして、夏頃にトライアルの機会をいただいてEMRから置き換えを試してみて気になったポイントなどを発表いたしました。

発表スケジュールをみていただくとわかりますが、クラスメソッドの小澤さんとの共同発表というかたちとなっており、まさかの近いタイトル(「Cloudera AltusとAmazon EMRを比較する」、「Amazon EMR利用者がCloudera Altusを使ってみた感想」)でほぼ同じ内容になってしまうのではないかと発表前不安だったのですが、フタをあけてみればそれぞれ違った視点での発表となっておりましてホッとしました。

順序は小澤さんの発表が先だったのですが、EMRとAltusの比較をわかりやすく語ってくれたおかげでより発表しやすくなり、一緒にやってよかったなぁと勝手に思っております。

イベントについて

個人的にKuduについて注目しておりその発表を聞けたことと、Clouderaの方に質問できて満足です。また、Cloudera World Tokyoはかれこれ5回参加しておりまして、毎年徐々にクラウドで運用しているところも増えているなと感じておりますが、今回発表の題材でもあったAltusを足がかりに、既存の資産を生かしながらジョブを少しずつクラウドに移行するところも増えるのではないかな、という気がしました。

個人的にもう一つの目的だった「仕事ではじめる機械学習」の限定プリント・オン・デマンド版をゲットできました。 ゲットした本は写真のようにGunosyライブラリの蔵書として追加されました!

f:id:s-wool:20171109193527j:plain:w300

Gunosyでは書籍購入制度を利用しての積極的な学習を支援しております!

最後に

Gunosyでは高速なAPIと機械学習で広告を最適に届けることに挑戦するエンジニアを募集中です!

hrmos.co hrmos.co hrmos.co

Gunosy Tech Night #7を開催しました!

f:id:gushunsuke:20171101144730j:plain こんにちは。グノシーの広告技術部を担当している有井です。

2017年10月25日(水)に社内勉強会であるGunosy Tech Nightを開催したのでレポートします!

Gunosy Tech Nightとは?

Gunosyでは、社内の各プロダクトを開発する事業部間の技術共有とエンジニア間の交流を深めることを目的に、月に1回社内勉強会としてTech Nightを開催しています。

毎回担当となる事業部が、アーキテクチャ概要や導入してよかった技術などの発表を行います。

当日はコーヒーや軽食が出されリラックスした雰囲気で行われます。 夜の開催になるとアルコールがでることもあります。

f:id:gushunsuke:20171101174749p:plain

発表内容

Tech Night初になる本人のことを知ってもらうための発表です。

得意な技術領域の話や、プライベートで寸胴でラーメンを作っている話など盛りだくさん。 どういう経緯でGunosyに入ったのか、これからどういう意気込みで働こうと思っているかなど、 自分も初心に振り返られるいい発表でした。

気軽に飲みやランチに誘いやすくなるので自己紹介を長めにやるのっていいですね。

Amazon EMR利用者がCloudera Altusを使ってみた感想

11月7日にCloudera World Tokyo 2017で登壇する内容の発表です。

www.clouderaworldtokyo.com

実際に管理画面を見ながらの比較や、使ってみた感想があり面白い発表でした。

気になる方は当日参加してみてください。

アドを支えるGoの話

広告のクリック率やコンバージョン率を高めるために導入したオンライン予測の仕組みに関する発表です。

計算量の多い処理の効率化や学習モデルのロード時間短縮といった様々なチューニングについての体験を語ってくれました。 予測ロジックをオンラインで実現するためにどういったことが課題になるかがわかり、非常に勉強になりました。

最後に

以上、Gunosy Tech Night#7のレポートでした!

内部向けの勉強会のため詳しい発表内容をお伝えできず申し訳ないです。 もっと詳細な発表内容を知りたい!という方はご応募頂ければと思います!

もちろん、Tech Nightを一緒に盛り上げたい!という方のご応募もお待ちしています!!

皆様のエントリーをお待ちしております!

hrmos.co

GunosyにMasashiSalvadorさんがJoinしました!

新規事業開発室の高橋(@__timakin__) です。

11/1付でMasashiSalvador さんがGunosyにジョインしました!手に持っているのはシロクマの人形です。

f:id:u_tis:20171101120232g:plain

サルバさんはDeNAやエウレカでのアドテク基盤や課金設計、チーム責任者を経て、旅行系サービスの起業、その後GunosyにJoinしてくださいました。好きな言語はSwiftだそうです。

学生時代は理化学研究所のBSIというところで、海馬の空間記憶の計算モデルについての研究をされていたそうです。

弊社はGunosy開発チームで動画周りをはじめとして力になってくださいます。これからよろしくお願いします!

なお、弊社では引き続き多くの部署で人材を募集しています。ぜひご応募ください!

hrmos.co

hrmos.co

hrmos.co