reizist's blog

ウェブ

golangの勉強をしている

golang楽しい

golangを勉強している

とはいえ面倒は面倒

やはりruby使いとしてはrubyの手軽さはプログラミング初心者に対して間違いなくプログラミングのハードルを下げているし重要な要素だと思った。

例えば文字列中の変数展開をするとか、Array#map とか、エコシステムが整いまくっててだいだいやりたいことはgemになっていて小回りがきくとかは圧倒的に楽だなぁと改めて思う。

話は変わるが勉強がてら社内で使っている踏み台経由でec2インスタンスのリストを取得しいい感じにsshするcligolangに移植しようと試みたが、

rubyでは

exec("ssh user@ip_addr -p port -o 'ProxyCommand ssh bastion_user@bastion_host -p bastion_port -i ~/.ssh/id_rsa -W %h:%p'")

で済んでしまう実装がうまいことgolangで動いておらずに困っている

いろいろと基本を理解していない恐れもあるのでもう少し基本に立ち返りつつ適当にcliを実装するサイクルを回してみようかなーと思う。

雑魚いなーとか思う人いたらほんとに教えてほしいので PRくださいw

github.com

SRE本読書会をやってみる #srelounge

SRE Loungeに参加して、改めてSRE本の重要性を感じたのでSRE本読書会を開催します

記念すべき第一回開催は9/28日(金) 19時〜

ポリシー

  • 会の開催コストを最小化
    • 予習はしない。しちゃだめ。
  • 会によるアウトプットを随時行いしおり化
    • それぞれの会で前回の振り返り/会のまとめを行いいつでもワードベースでキャッチアップ可能にできたらいいな

フォーマット

  • 前回の振り返り(〜10min)
    • 新たな章に進むにあたり今までの重要事項を振り返る
  • 章を読む(〜15min)
    • 1回につき1章が望ましいが開催しつつ読むスピードを考慮して分割を検討する
    • 読みつつ気になったワードや事柄をメモ
  • 思考/議論(〜20min)
    • 上記でメモした内容についてググったり議論を行い知識の定着化を行う
    • scrapboxでメモをとるとよさそう
  • まとめ(〜15min)
    • scrapbox(メモ)の整理と次回の内容の確認/開催日の決定などの必要な準備を行う

備考

  • はじめから「誰かやろうぜ!」とかだとぐだるので自分のモチベーションドリブンでまず開催してみる 
  • とはいえどの回からでも(社内の)誰でも参加可能なようにまとめる努力はしてみる

ECRのイメージ管理がしやすくなっていた

ecsでサービスを動かす場合、大抵の場合は自前イメージをecrに置くことになるんじゃないでしょうか。 ecrには 1000 images/ 1repo というイメージ保有制限が存在し、定期的なクリーンが必要ですが、最近のアップデートでかなり対応しやすくなっていたので共有です

どうやるの

ecrにライフサイクルポリシーを設定します。terraform的にはこうです

resource "aws_ecr_lifecycle_policy" "ecr_image_clean_lifecycle_policy" {
  count      = "${ length(var.ecr-repos) }"
  repository = "${ element(var.ecr-repos), count.index) }"

  policy = <<EOF
{
    "rules": [
        {
            "rulePriority": 1,
            "description": "Expire excess images more than 100",
            "selection": {
                "tagStatus": "any",
                "countType": "imageCountMoreThan",
                "countNumber": 100
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}
EOF
}

variable "ecr-repos" {
  type    = "list"
  default = ["your-great-repo-name"]
}

補足

ちなみにどうやら先々月にライフサイクルポリシー更新され使いやすくなっていて、 対象のイメージフィルタとして

  • タグ
  • 個数
  • 期間

が存在しましたが、以前はタグ付けされているimageの場合prefixを指定する必要がありました。 つまり git sha1などを使いタグ付けをしていた場合はこれらをフィルタできず、実質タグのないimageのみ削除が可能という微妙な感じだったようです。(ちなみに前にいた会社ではcircle ciでcapistrano task経由によりimage clean scriptを走らせていました) 

今回追加された tagStatus: any により、タグ付けされたものも一括で消せるようになり、圧倒的に便利になったのでこれでいけますね。

https://aws.amazon.com/jp/about-aws/whats-new/2018/07/amazon-ecr-lifecycle-policies-adds-filtering-option-for-tagged-i/

redashを0.12 -> 4.0.1のアップグレードした作業ログ

(あまりまともに運用されていない)redashがもともとredash-v0.12.0.b2449 で動いていたが Redash1.0.3で日本語を含むTreasureDataのクエリがエラーになるらしい という報告をもらい対応を検討した結果、容易にアップグレードできそうだったので対応してみたところハマった

背景

http://blog.web.nifty.com/engineer/701

のように、古いredashではtd-clientのversionが古く日本語を含むクエリが動かないのでアップグレードしてほしい、という軽い相談を受けた。

前述のブログによれば td-client が0.8.0以降で改修されているという記述があったので試してみたところ、 Error running query: job error: 328215861: error という謎のエラーが発生し解決しなかった。

pip install td-client==0.8.0
pip list  | grep td-client
supervisorctl restart all

redashのupgradeについて調査をしてみたところ、 https://redash.io/help/open-source/admin-guide/how-to-upgrade にキレイにアップグレードの方法がまとまっていたので、数年前のredashを積極的に使う理由もないし簡単にできそうだったのでアップグレードをすることにした。 なおコンテナで動かす方向も検討したが、redashはそれまでほぼ誰も使っておらず今後の使用頻度にもあまり期待はできなさそうだったのでアップグレードを採用した。

何にハマったか

今回は0.12 -> latestのupgradeだったので前述のリンクの

How to upgrade (pre v1.0.0 versions)

に該当し、記述通りの対応を行った。

cd /opt/redash
sudo cp -r redash-v0.12.0.b2449 redash-v0.12.0.b2449-backup
cd /opt/redash/current
wget https://raw.githubusercontent.com/getredash/redash/master/bin/upgrade
chmod +x upgrade
vim .env # REDASH_STATIC_ASSETS_PATHを消す
sudo ./upgrade

実行したところ、

Downloading release tarball...
Unpacking to: redash.4.0.1.b4038...
Changing ownership to redash...
Linking .env file...
Installing new Python packages (if needed)...
Running migrations (if needed)...

とログが流れ、最後のmigrationが時間がかかっているようだったのでバックグランド実行に切り替え退社(20:30)し、優雅にジムに行き2km泳ぎ、気分良く帰宅し「よーしmigration終わったやろ」と言って psql して SELECT * FROM pg_stat_activity; した(1:30)ところ、 idle in transaction で数時間止まっているクエリを発見した。 migrationが終わっていない.... ひとまずmigrationが問題であることがわかったのでmigrationを単体で実行してみる。

[ec2-user@ip-xxx-xxx-xxx-xxx redash.4.0.1.b4038]$ pwd
/opt/redash/redash.4.0.1.b4038
bin/run ./manage.py db upgrade

しかし、 Update widget’s position data based on dashboard layout. Updating dashboards position data: でstuckして十数分待ってもmigrationが終わらない。

どうしたものかと思いぐぐったところ、全く同じ現象でハマッた人がおり、 0.12 -> 4.0.1の前に 3.0を経由したら動いた とのことだった。 んなアホな

物は試しと3.0へのupgradeを試みる。 アップグレード対象のversionはどうやらAPIから取得しているようだった。

def get_release(channel):
    if channel == 'ci':
        return get_latest_release_from_ci()

    response = requests.get('https://version.redash.io/api/releases?channel={}'.format(channel))
    release = response.json()[0]

    filename = release['download_url'].split('/')[-1]
    release = Release(release['version'], release['download_url'], filename, release['description'])

    return release

APIのレスポンスを見ると、

[{"id":28,"version":"4.0.1","channel":"stable","download_url":"https://s3.amazonaws.com/redash-releases/redash.4.0.1.b4038.tar.gz","backward_compatible":false,"released_at":"2018-05-02T00:00:00.000Z","description":"* Before doing an upgrade, please make sure you have a backup.\n* If you have any issues, please refer to the troubleshooting section in the upgrade guide:\n  https://redash.io/help/open-source/admin-guide/how-to-upgrade\n* If the upgrade guide doesn't help, you can ask for help on the forum (https://discuss.redash.io).   \n\nFull CHANGELOG for this release: https://github.com/getredash/redash/blob/master/CHANGELOG.md","docker_image":"redash/redash:4.0.1.b4038"},{"id":27,"version":"4.0.0","channel":"stable","download_url":"https://s3.amazonaws.com/redash-releases/redash.4.0.0.b3948.tar.gz","backward_compatible":false,"released_at":"2018-04-16T00:00:00.000Z","description":"* Before doing an upgrade, please make sure you have a backup.\n* If you have any issues, please refer to the troubleshooting section in the upgrade guide:\n  https://redash.io/help/open-source/admin-guide/how-to-upgrade\n* If the upgrade guide doesn't help, you can ask for help on the forum (https://discuss.redash.io).   \n\nFull CHANGELOG for this release: https://github.com/getredash/redash/blob/master/CHANGELOG.md","docker_image":"redash/redash:4.0.0.b3948"},{"id":23,"version":"3.0.0","channel":"stable","download_url":"https://s3.amazonaws.com/redash-releases/redash.3.0.0.b3134.tar.gz","backward_compatible":true,"released_at":"2017-11-13T00:00:00.000Z","description":"* Before doing an upgrade, please make sure you have a backup.\n* If you have any issues, please refer to the troubleshooting section in the upgrade guide:\n  https://redash.io/help-onpremise/maintenance/how-to-upgrade-redash.html\n* If the upgrade guide doesn't help, you can ask for help on the forum (https://discuss.redash.io).   \n\nFull CHANGELOG for this release: https://github.com/getredash/redash/blob/master/CHANGELOG.md","docker_image":"redash/redash:3.0.0.b3134"},{"id":22,"version":"2.0.1","channel":"stable","download_url":"https://s3.amazonaws.com/redash-releases/redash.2.0.1.b3080.tar.gz","backward_compatible":true,"released_at":"2017-10-22T00:00:00.000Z","description":"* Before doing an upgrade, please make sure you have a backup.\n* If you have any issues, please refer to the troubleshooting section in the upgrade guide:\n  https://redash.io/help-onpremise/maintenance/how-to-upgrade-redash.html\n* If the upgrade guide doesn't help, you can ask for help on the forum (https://discuss.redash.io).   \n\nFull CHANGELOG for this release:\nhttps://github.com/getredash/redash/blob/master/CHANGELOG.md#v201---2017-10-22","docker_image":null},{"id":21,"version":"2.0.0","channel":"stable","download_url":"https://s3.amazonaws.com/redash-releases/redash.2.0.0.b2990.tar.gz","backward_compatible":true,"released_at":"2017-08-08T00:00:00.000Z","description":"* Before doing an upgrade, please make sure you have a backup.\n* If you have any issues, please refer to the troubleshooting section in the upgrade guide:\n  https://redash.io/help-onpremise/maintenance/how-to-upgrade-redash.html\n* If the upgrade guide doesn't help, you can ask for help on the forum (https://discuss.redash.io).   \n\nFull CHANGELOG for this release: https://github.com/getredash/redash/blob/master/CHANGELOG.md#v200---2017-08-08","docker_image":null}]

のようになっておりchannel: stableの3つめのレスポンスを使えばよさそうということがわかったので、

- release = response.json()[0]
+ release = response.json()[2]

とし

sudo ./upgrade --channel stable

を実行したところ、速攻3.0へのupgradeが終わってしまった。なんでやねん...と思いつつもう一度upgradeを実行したところ素直に4.0.1にあがった。 なんでやねん

所感

  • ゴリ押し感半端ない
  • 素直にcontainerで動かせばこんな苦労はないので、僕のような悪い大人にはならないようにしましょう

補足

redash4.0にあげたことによりクエリ失敗時のエラーログに詳細の理由が出るようになった結果、 今回のクエリは

Error running query: job error: 328361382: error: Query 20180814_173306_79597_yerrm failed: line 15:12: Table td-presto.xxx.xxx_orders does not exist

というように失敗していたので別の理由もあったことがわかり結果的にはredashあげてよかったですね。

prestodbにおけるelapsed timeとは何か

prestodbを扱っていてクエリメトリクスを見る上で必ず参照することになるelapsed timeが一体何なのかを調べたメモ。 一言でいうとクエリが作成されてからクエリが完了するまでの時間なんだけど、じゃあそれがいつなのかというのをソースを追う。

全体の流れを追うのに、

https://www.slideshare.net/frsyuki/hadoop-source-code-reading-15-in-japan-presto

https://image.slidesharecdn.com/hsr15-presto-131223202205-phpapp01/95/hadoop-source-code-reading-15-in-japan-presto-10-638.jpg?cb=1387830178

presto_executor_and_coordinator.md · GitHub

あたりが非常に参考になるので足がかりにするとよい。

実際に createTime , endTime を作成しているのは QueryStateMachine 内で、

https://github.com/prestodb/presto/blob/bcfb4c6f2872f9de39c0e8f42c6bd43dd08241c2/presto-main/src/main/java/com/facebook/presto/execution/QueryStateMachine.java#L90

  • endTime : recordDoneStats() コール時
    • transitionToFinished() or transitionToFailed() or transitionToCanceled() の処理内で recordDoneStats() が呼ばれる

https://github.com/prestodb/presto/blob/bcfb4c6f2872f9de39c0e8f42c6bd43dd08241c2/presto-main/src/main/java/com/facebook/presto/execution/QueryStateMachine.java#L657

実際に QueryStateMachineインスタンスSqlQueryExecution のコンストラクタ内で作成され、 transitionToXXX()com.google.common.util.concurrent.Futures#addCallback() によって onSuccess() などのcallbackとして処理される。

https://github.com/prestodb/presto/blob/bcfb4c6f2872f9de39c0e8f42c6bd43dd08241c2/presto-main/src/main/java/com/facebook/presto/execution/QueryStateMachine.java#L636

SqlQueryExecution のオブジェクトは SqlQueryManager#createQuery によって作成される。

https://github.com/prestodb/presto/blob/dba2648ddc34875aa8b4f8e32a4dba7ba5920e0d/presto-main/src/main/java/com/facebook/presto/execution/SqlQueryManager.java#L412


メトリクスを把握するのによく参照する時間周りのまとめ。

タイプ 処理クラス
createTime クエリ作成時間 QueryStateMachine
startTime 実際のクエリ処理開始時間 Session
endTime 実際のクエリ処理完了時間 QueryStateMachine
queuedTime duration(startTime - createTime) QueryStateMachine
elapsedTime duration(endTime - createTime) QueryStateMachine
executionTime elapsedTime - queuedTime QueryStats

雑いけどひとまずメモ。

mac上のhiveのデータストアにS3を使う

reizist.hatenablog.com

の続き。

EXTERNAL TABLEのLOCATIONにS3を使う場合の設定。

やることは2つ。

  • S3AFileSystemを使うために2つファイルを編集してパスを通す

$HADOOP_CONF_DIR/hadoop-env.sh

export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$HADOOP_HOME/libexec/share/hadoop/tools/lib/*
  • S3AFileSystemの指定とアクセスキーの設定

$HADOOP_CONF_DIR/yarn-site.xml

<?xml version="1.0"?>
<configuration>
  <property>
    <name>fs.s3a.impl</name>
    <value>org.apache.hadoop.fs.s3a.S3AFileSystem</value>
  </property>
  <property>
    <name>fs.s3a.access.key</name>
    <value>AWSのアクセスキー</value>
  </property>
  <property>
    <name>fs.s3a.secret.key</name>
    <value>AWSのシークレットキー</value>
  </property>
</configuration>

hadoop fs -ls s3a://bucket名/ で疎通が確認とれればOK。

java.lang.RuntimeException: java.lang.ClassNotFoundException: Class org.apache.hadoop.fs.s3a.S3AFileSystem not found

が発生した場合、正しくパスが通ってない。

mac上にhive+hive metastore on mysql環境を構築する

hadoop & hive on macの環境構築記事結構ちらほらあるんだけど、その通りにやって動かなかったり、信頼に欠けるコメントがついていたりするので改めて自分でまとめる。

hadoop + hive + hive metastore on mysqlを想定してます。

環境

準備

java

$ brew cask install java

$ echo 'export JAVA_HOME=`/usr/libexec/java_home -v 1.8`' >> ~/.zshrc
$ echo 'export PATH="PATH=$JAVA_HOME/bin:$PATH"' >> ~/.zshrc

mysql

$ brew install mysql

hadoop

$ brew install hadoop

$ echo 'export HADOOP_HOME="/usr/local/Cellar/hadoop/2.8.2"' >> ~/.zshrc
$ echo 'export HADOOP_CONF_DIR="$HADOOP_HOME/libexec/etc/hadoop"' >> ~/.zshrc

$HADOOP_CONF_DIR 上で2つの設定ファイルを追加

  • core-site.xml
<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://localhost:9000</value>
    </property>
</configuration>
<configuration>
    <property>
        <name>dfs.name.dir</name>
        <value>/var/lib/hdfs/name</value>
    </property>
    <property>
        <name>dfs.data.dir</name>
        <value>/var/lib/hdfs/data</value>
    </property>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
</configuration>

hive

$ brew install hive
$ echo 'export HIVE_HOME="/usr/local/Cellar/hive/2.3.1"' >> ~/.zshrc
$ echo 'export HIVE_CONF_DIR="$HIVE_HOME/libexec/conf"' >> ~/.zshrc

$HIVE_CONF_DIR 上で1つの設定ファイルを追加( cp hive-default.xml.template hive-site.xml としても可)

  • hive-site.xml
<property>
  <name>javax.jdo.option.ConnectionURL</name>
  <value>jdbc:mysql://localhost/hive_metastore</value>
</property>
<property>
  <name>javax.jdo.option.ConnectionDriverName</name>
  <value>com.mysql.jdbc.Driver</value>
</property>
<property>
  <name>javax.jdo.option.ConnectionUserName</name>
  <value>[mysql上に構築するhive metastore用dbにつなぐユーザー名 e.g. hive]</value>
</property>
<property>
  <name>javax.jdo.option.ConnectionPassword</name>
  <value>[mysql上に構築するhive metastore用dbにつなぐユーザー名 e.g. password]</value>
</property>
<property>
    <name>hive.exec.local.scratchdir</name>
    <value>/tmp/hive</value>
    <description>Local scratch space for Hive jobs</description>
</property>
<property>
    <name>hive.downloaded.resources.dir</name>
    <value>/tmp/hive</value>
    <description>Temporary local directory for added resources in the remote file system.</description>
</property>
<property>
    <name>hive.querylog.location</name>
    <value>/tmp/hive</value>
    <description>Location of Hive run time structured log file</description>
</property>

hive metastore接続用JDBCドライバを配置

$ curl -O https://cdn.mysql.com/Downloads/Connector-J/mysql-connector-java-5.1.44.tar.gz
$ tar xvzf mysql-connector-java-5.1.44.tar.gz
$ mv mysql-connector-java-5.1.44/mysql-connector-java-5.1.44-bin.jar $HIVE_HOME/lib

localhostへのssh

システム環境設定→共有→リモートログインをON

設定

hadoop hdfsフォーマット

$ hdfs namenode -format

mysqlにhive metastore用環境準備

  • FAQによれば、 When using MySQL as a metastore I see the error "com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Specified key was too long; max key length is 767 bytes". に対する回避策としてcharacter setに latin1 を使うパターンを記載しています。手っ取り早いのでこれで対応
$ mysql -u root
mysql> create database hive_metastore default character set 'latin1';
mysql> use hive_metastore;
mysql> create user 'hive'@'localhost' identified by 'password';

metastore用のテーブル初期化作成

$ schematool -dbType mysql -initSchema -verbose

Unable to instantiate org.apache.hadoop.hive.metastore.HiveMetaStoreClient が出る場合はmysqlにmetastoreテーブルが作られているか確認する

$ mysql -u hive -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 836
Server version: 5.7.19 Homebrew

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use hive_metastore;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;

hive側からmetastoreにアクセスできればOK

$ hive
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/local/Cellar/hive/2.3.1/libexec/lib/log4j-slf4j-impl-2.6.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/usr/local/Cellar/hadoop/2.8.2/libexec/share/hadoop/common/lib/slf4j-log4j12-1.7.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
show tables;

Logging initialized using configuration in jar:file:/usr/local/Cellar/hive/2.3.1/libexec/lib/hive-common-2.3.1.jar!/hive-log4j2.properties Async: true
Hive-on-MR is deprecated in Hive 2 and may not be available in the future versions. Consider using a different execution engine (i.e. spark, tez) or using Hive 1.X releases.
hive> show tables;
OK
Time taken: 3.35 seconds
hive>

何かしらのエラーが発生する場合

hive -hiveconf hive.root.logger=DEBUG,console

としてログを見る。

hiveの細かいプロパティはConfiguration Properties 参照。例えば datanucleus.schema.autoCreateAll (hive2.0以降は datanucleus.autoCreateSchema ではない)を有効にすると初回起動時のメタストア作成を自動的に行なってくれる。