Apr 27, 2018

New EOM Style

仕事で使っているとある製品が結構な量の不具合がある状態で、EOMになってしまい悲しい。不具合のある部分はJavaで実装されていたので、jadで逆コンパイラを行い修正する箇所のあたりをつけてから、dirtyJOEでclassファイルを直接修正してみたんですが、結果的には直らず...。関連する全classファイルのpackageパスを変更すれば直りそうなことはわかったんですが、それはさすがに大変すぎるので諦めました。EOMにするならコア部分は公開しないにせよ、バグに関わる部分だけでもそのユーザーに公開することができれば、みんなハッピーになれるのではと思ったりします。

森博嗣さんの百年シリーズ 1作目の「女王の百年密室」を読み終わりました。Wシリーズ、Xシリーズ、百年シリーズと読んでいて、共通して面白いと思うのは、主人公とその主人公を支える人間もしくはウォーカロンの会話でしょうか。Wシリーズならハギリとウグイ、Xシリーズなら小川と真鍋、百年シリーズならサエバ・ミチルとロイディ。ハギリとデボラの会話も好きですが、巻を重ねるにつれウグイの良さがより際立っていると僕は感じます。Wシリーズはそろそろ終わりの雰囲気が出ていて若干寂しいですが、最後まで楽しみです。

Apr 17, 2018

Kubernetes Up & Running


入門 Kubernetesを読みました。本の中で紹介されているyamlはkubernetes-up-and-running/examplesにあるみたいです。

# Docker
docker run -d --name kuard --publish 8081:8080 --memory 200m --memory-swap 1G --cpu-shares 1024 gcr.io/kuar-demo/kuard-amd64:1
docker stop kuard; docker rm kuard

# Kubernetes
kubectl version
kubectl get componentstatuses

controller-manager' クラスタ上の振る舞いを制御する
scheduler 各Podをクラスタ内のそれぞれのノードに配置する
etcd クラスタのすべてのAPIオブジェクトが保存されるストレージ

ノードの表示する
kubectl get nodes
masterノード APIサーバーやスケジューラのコンテナが動く
workerノード ユーザが作成したコンテナが動く

特定ノードの表示する
kubectl describe nodes xxx

プロキシの一覧を表示する
kubectl get daemonSets --namespace=kube-system kube-proxy

DNSの一覧を表示する
kubectl get deployments --namespace=kube-system kube-dns

DNSサーバをロードバランシングするためのKubernetes Serviceを表示する
kubectl get services --namespace=kube-system kube-dns

UIサーバの確認
kubectl get deployments --namespace=kube-system kube-dashboard

ロードバランスのためのServiceを表示
kubectl get services --namespace=kube-system kube-dashboard

UIにアクセスする
kubectl proxy

# よく使うkubectlコマンド
Namespaceはオブジェクトの集まりを入れるフォルダのようなイメージ

実行中のコンテナのログを確認する
kubectl logs podname
kubectl logs -f podname

ファイルのやりとりを行う
kubectl cp podname:/path/to/remote/file /path/to/local/file

実行中のコンテナにログインする
kubectl exec -it podname -- bash

Kubernetesではコンテナではなく、Podが最小のデプロイ単位であり、1つのPodないのコンテナはすべて同じマシン上に配置される
スケールさせる時もPod単位なので、例えばWordPressとMySQLを同じPodにすると片方だけスケールさせることができない
コンテナが違うマシンに配置されても正常に動作できるのであれば、Podを分けるのが正解な可能性が高い

Podの作成、確認、削除
kubectl run kuard --image=gcr.io/kuar-demo/kuard-amd64:1
kubectl get pods
kubectl delete deployments/kuard

Podをyamlで作成する
apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:1
      name: kuard
      ports:
        - containerPort: 8081
          name: http
          protocol: TCP

kubectl apply -f kuard-pod.yaml

Podの詳しい情報の確認
kubectl describe pods kuard

詳細を確認するオプション
kubectl get pods -o wide
kubectl get pods -o json
kubectl get pods -o yaml

Podの削除
kubectl delete pods/kuard
kubectl delete -f kuard-pod.yaml

Podの削除コマンドを実行した時に、まずTerminatingという状態になりデフォルト30秒の猶予期間(grace period)後に削除される。Terminating状態になるとそのPodはリクエストを受け付けない。この猶予期間によって処理中の可能性のあるリクエストをPodを削除する前に終わられることができる。

ポートフォワード(コマンド実行中のみ有効)
kubectl port-forward kuard 8081:8080

ログの確認
kubectl logs kuard
kubectl logs -f kuard
kubectl logs --previous kuard

ヘルスチェック
プロセスヘルスチェック機能によってアプリケーションのメインプロセスが動いているか常に監視し、動いていない場合はKubernetesがプロセスを再起動する。プロセスが生きているものの、リクエストには応答できていない場合にはこれだけでは対応できない。

Liveness probe
apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:1
      name: kuard
      livenessProbe:
        httpGet:
          path: /healthy
          port: 8080
        initialDelaySeconds: 5
        timeoutSeconds: 1
        periodSeconds: 10
        failureThreshold: 3
      ports:
        - containerPort: 8081
          name: http
          protocol: TCP

initialDelaySecondsはPod内の全コンテナが作成されてから5秒経過するまでリクエストを送らない
timeoutSecondsの1秒以内に応答する必要がある
HTTPチェックだけでなくtcpSocketもサポートしている
exec監視も可能で、コンテナ内でスクリプトの返り値が0なら成功、0以外なら失敗のようなこともできる
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/

リソース要求 最低限必要なリソース
リソース制限 最大リソース量
apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:1
      name: kuard
      resources:
        requests:
          cpu: "500m"
          memory: "128Mi"
      ports:
        - containerPort: 8081
          name: http
          protocol: TCP
1CPUの半分および128MBをリソース要求に設定する例
CPUのリソース要求はLinuxカーネルのcpu-shares機能を使って実装されている

apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:1
      name: kuard
      resources:
        requests:
          cpu: "500m"
          memory: "128Mi"
        limits:
          cpu: "1000m"
          memory: "256Mi"         
      ports:
        - containerPort: 8081
          name: http
          protocol: TCP
リソース制限に1CPU、メモリ256MBを設定する例

データの永続化
spec.volumnsセクションもしくはvolumnMountsを使用する
apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  volumes:
    - name: "kuard-data"
      hostPath:
        path: "/var/lib/kuard"
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:1
      name: kuard
      volumeMounts:
        - mountPath: "/data"
          name: "kuard-data"
      ports:
        - containerPort: 8081
          name: http
          protocol: TCP
kuard-dataというボリュームを定義し、kuardコンテナの/dataにマウントする例
empDirはキャッシュに便利
NFSサーバーを利用することも可能
  volumes:
    - name: "kuard-data"
      nfs:
        server: my.nfs.server.local
        path: "/exports"


# LabelとAnnotation
LabelとAnnotationの使い分けは、好みにもよる。セレクタとして使いたくなったらLabelに昇格させるのが良い

kubectl run alpaca-prod --image=gcr.io/kuar-demo/kuard-amd64:1 --replicas=2 --labels="ver=1,app=alpaca,env=prod"
kubectl run alpaca-test --image=gcr.io/kuar-demo/kuard-amd64:2 --replicas=1 --labels="ver=2,app=alpaca,env=test"
kubectl run bandicoot-prod --image=gcr.io/kuar-demo/kuard-amd64:2 --replicas=2 --labels="ver=2,app=bandicoot,env=prod"
kubectl run bandicoot-staging --image=gcr.io/kuar-demo/kuard-amd64:2 --replicas=1 --labels="ver=2,app=bandicoot,env=staging"

Labelの確認
kubectl get deployments --show-labels
kubectl get deployments -L env
kubectl get pods --selector="ver=2"
kubectl get pods --selector="ver!=2"
kubectl get pods --selector="app=bandicoot,ver=2"
kubectl get pods --selector="app in (alpaca,bandicoot)"
kubectl get pods --selector="app notin (alpaca,bandicoot)"
kubectl get deployments --selector="canary"
kubectl get deployments --selector="!canary"

Labelの追加(ReplicaSetやPodは変更されないので注意)
kubectl label deployments alpaca-test "canary=true"

Deploymentの削除
kubectl delete deployments --selector="canary"
kubectl delete deployments --all

# サービスディスカバリ
kubectl run alpaca-prod --image=gcr.io/kuar-demo/kuard-amd64:1 --replicas=3 --port=8080 --labels="ver=1,app=alpaca,env=prod"
kubectl expose deployment alpaca-prod
kubectl run bandicoot-prod --image=gcr.io/kuar-demo/kuard-amd64:2 --replicas=2 --port=8080 --labels="ver=2,app=bandicoot,env=prod"


kubectl expose deployment bandicoot-prod
kubectl get services -o wide

ALPACA_POD=$(kubectl get pods -l app=alpaca -o jsonpath='{.items[0].metadata.name}')
kubectl port-forward $ALPACA_POD 48858:8080

Readiness probe
kubectl edit deployment/alpaca-prod

    spec:
      containers:
      - image: gcr.io/kuar-demo/kuard-amd64:1
        imagePullPolicy: IfNotPresent
        name: alpaca-prod
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          periodSeconds: 2
          initialDelaySeconds: 0
          failureThreshold: 3
          successThreshold: 1
        ports:
        - containerPort: 8080
          protocol: TCP

ServiceのEndpointsに対するトラフィックの確認
kubectl get endpoints alpaca-prod --watch

Endpointsオブジェクトの確認
kubectl describe endpoints alpaca-prod

新しいServiceが作られるとkube-proxyは、iptablesのルールをホストのカーネルに設定する

# ReplicaSet
冗長性、スケール、シャーディングのために用意されているのがReplicaSet
ReplicaSetはPodのLabelを使ってクラスタの状態を監視する
不具合のあるPodのLabelだけを変更し、 ReplicaSetからPodを切り離すと、Podは起動したままになるのでデバッグがしやすくなる

ReplicaSetの最小限の定義例(kuard-rs.yaml)
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
  name: kuard-rs
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: kuard
        version: "2"
    spec:
      containers:
        - name: kuard
          image: "gcr.io/kuar-demo/kuard-amd64:2"
kubectl apply -f kuard-rs.yaml

PodからReplicaSetの特定
kubectl get pods kuard-rs-4m2nj -o yaml | grep owner -A 

ReplicaSetに対応するPodの集合の特定
kubectl get pods -l app=kuard,version=2

kubectl scaleを使った命令的スケール(もし使用する場合はyamlも書き換えること)
kubectl scale replicasets kuard-rs --replicas=4

宣言的スケール
yamlのreplicasの値を書き換え後にkubectl apply -f kuard-rs.yaml

水平Podオートスケーリング(HPA Horizontal Pod Autoscaling)
heapsterというPodによりメトリクスを追跡し、HPAがスケーリングの判断を行う時に使用するメトリクスを取得するAPIを提供する
クラスタ内にheapsterが存在しない場合はHPAは正常に動作しない
Podのレプリカを追加することを水平スケール、Podに必要なリソースを増やすことを垂直スケールと区別している

CPU使用率を元にしたオートスケール
kubectl autoscale rs kuard-rs --min=2 --max=5 --cpu-percent=80
CPU使用率80%を閾値にして、レプリカ数2〜5の間でスケールするオートスケーラ

確認
kubectl get hpa

ReplicaSetを削除すると管理しているPodも一緒に削除される
kubectl delete rs kuard-rs

ReplicaSetのみ削除したい場合
kubectl delete rs kuard-rs --cascade=false

# Daemon Set
ReplicaSetと違い、ノードセレクタを使わない限り、全ノードにPodを作る

fluentd.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-system
  labels:
    app: fluentd
spec:
  template:
    metadata:
      labels:
        app: fluentd
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd:v0.14.10
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
kubectl apply -f fluentd.yaml

NodeにLabelを追加し、確認
kubectl label nodes minikube ssd=true
kubectl get nodes --show-lables
kubectl get nodes --selector ssd

nginx-fast-storage.yaml(ssd=trueというLabelがノードでのみ動くDaemonSet)
apiVersion: extensions/v1beta1
kind: "DaemonSet"
metadata:
  labels:
    app: nginx
    ssd: "true"
  name: nginx-fast-storage
spec:
  template:
    metadata:
      labels:
        app: nginx
        ssd: "true"
    spec:
      nodeSelector:
        ssd: "true"
      containers:
        - name: nginx
          image: nginx:1.10.0
他のノードにssd=trueというLabelを追加すれば、そのノードにもデプロイされる。逆にLabelを削除するとそのPodはDaemonSetコントローラから削除される

forループを用いたPodの削除
PODS=$(kubectl get pods -o jsonpath -template='{.ites[*].metadata.name}')
for x in $PODS; do
  kubectl delete pods ${x}
  sleep 60
done

ローリングアップデートを使うにはspec.updateStrategy.typeフィールドにRollingUpdateを設定する。ローリングアップデート中のステータスの確認はkubectl rolloutコマンドを使用する
kubectl rollout status daemonSets nginx-fast-storage

DaemonSetの削除
kubectl delete -f fluentd.yaml

# Job
1回限りの処理を行うのに便利なのがJobオブジェクト
kubectl run -i oneshot --image=gcr.io/kuar-demo/kuard-amd64:1 --restart=OnFailure -- --keygen-enable --keygen-exit-on-complete --keygen-num-to-gen 10
-iオプションはコマンドが対話モードであることを表す
--restart=OnFailureはkubectlにJobオブジェクトを作成するよう指示する

完了後のPodも含めて表示する
kubectl get pods -a

yamlでJobを作成する例
kubectl apply -f job-oneshot.yaml

失敗するJobの例
kubectl apply -f job-oneshot-failure1.yaml
kubectl get pods -a -l job-name=oneshot
KubernetesはこのPodがCrashLoopBackOffだと認識している。クラッシュの繰り返しによってノードのリソースが使われ過ぎないように、Podの再起動まで自動で少し待つ。
restartPolicy: Neverに設定するとkubeletはJob失敗時にPodを再起動せず、代わりにPodを失敗と宣言し、代わりのPodを作成する。restartPolicy: OnFailureにしておくことを推奨。

一定数成功するまで並列実行
kubectl apply -f job-parallel.yaml
kubectl get pods -w
--watchフラグによって時間とともにPodの一覧が更新されることを確認できる

並列実行キューを実装する例
1. 1回限りのキューデーモンを管理するために、ReplicaSetを作成する
kubectl apply -f rs-queue.yaml

2. キューに接続するためにポートフォワードを設定する
QUEUE_POD=$(kubectl get pods -l app=work-queue,component=queue -o jsonpath='{.items[0].metadata.name}')
kubectl port-forward $QUEUE_POD 8080:8080
MemQ Serverを開いてキューが動作していれば、キューのプロデューサとコンシューマがDNS経由でキューを使える状態。

3. キューのServiceを作成する
kubectl apply -f service-queue.yaml

4. サブタスクをキューに入れ、状態を確認
for in in work-item-{0..99}; do
  curl -X POST localhost:8080/memq/server/queues/keygen/enqueue -d "$i"
done
curl 127.0.0.1:8080/memq/server/stats

5. コンシューマJobを作成する
kubectl apply -f job-consumers.yaml
kubectl get podsで5つのPodが並列に動作していることがわかる

# ConfigMapとSecret
ConfigMapにはワークロードに応じた設定情報を保存する
SecretにはパスワードやTLS証明書などの機密情報を保存する

ConfigMapの作成
my-config.txt
parameter1 = value1
parameter2 = value2

kubectl create configmap my-config --from-file=my-config.txt --from-literal=extra-param=extra-value --from-literal=another-param=anather-value

kubectl get configmaps my-config -o yaml

ConfigMapの使用
kuard-config.yaml
apiVersion: v1
kind: Pod
metadata:
  name: kuard-config
spec:
  containers:
    - name: test-container
      image: gcr.io/kuar-demo/kuard-amd64:1
      imagePullPolicy: Always
      command:
        - "/kuard"
        - "$(EXTRA_PARAM)"
      env:
        - name: ANOTHER_PARAM
          valueFrom:
            configMapKeyRef:
              name: my-config
              key: another-param
        - name: EXTRA_PARAM
          valueFrom:
            configMapKeyRef:
              name: my-config
              key: extra-param
      volumeMounts:
        - name: config-volume
          mountPath: /config
  volumes:
    - name: config-volume
      configMap:
        name: my-config
  restartPolicy: Never
kubectl apply -f kuard-config.yaml
kubectl port-forward kuard-config 8080

Secretの作成
サンプルのTLSキーと証明書をダウンロードする(この例以外では使用しないこと)
curl -o kuard.crt https://storage.googleapis.com/kuar-demo/kuard.crt
curl -o kuard.key https://storage.googleapis.com/kuar-demo/kuard.key
kubectl create secret generic kuard-tls --from-file=kuard.crt --from-file=kuard.key
kubectl describe secrets kuard-tls

Secretの使用
今回の例ではSecret volumeを/tlsにマウントすると/tls/kuard.crtおよびtls/kuard.keyにアクセス可能になる
kuard-secret.yaml
apiVersion: v1
kind: Pod
metadata:
  name: kuard-tls
spec:
  containers:
    - name: kuard-tls
      image: gcr.io/kuar-demo/kuard-amd64:1
      imagePullPolicy: Always
      volumeMounts:
      - name: tls-certs
        mountPath: "/tls"
        readOnly: true
  volumes:
    - name: tls-certs
      secret:
        secretName: kuard-tls
kubectl apply -f kuard-secret.yaml
kubectl port-forward kuard-tls 8443:8443

プライベートDockerレジストリ
kubectl create secret docker-registry my-image-pull-secret \
 --docker-username=xxx \
 --docker-password=xxx \
 --docker-email=xxx
yamlのサンプル kuard-secret-ips.yaml

ConfigMapとSecretの管理
kubectl get secrets
kubectl get configmaps
kubectl describe configmap my-config

# Deployment
Deploymentを使うとダウンタイムやエラーを発生させずに新しいバージョンのソフトウェアをシンプルにロールアウトできる。
kubectl scale deployments nginx --replicas=2
Deploymentをスケールすると、その管理下にあるReplicaSetもスケールされる

kubectl get deployments nginx --export -o yaml > nginx-deployment.yaml
kubectl replace -f nginx-deployment.yaml --save-config
kubectl describe deployments nginx
ロールアウト中はOldReplicaSetsフィールドに値が入る

コマンドではなくyamlでスケールさせるには以下の部分を更新する
spec:
  replicas: 3

ロールアウトを中断・再開する
kubectl rollout pause deployments nginx
kubectl rollout resume deployments nginx

ロールアウトの履歴を確認する
kubectl rollout history deployments nginx
kubectl rollout history deployments nginx --revision=2

ロールアウトのロールバック
kubectl rollout undo deployments nginx

履歴の数を制限する方法
spec:
  revisionHistoryLimit: 14

Deployment戦略
Recreate: Deploymentに基づいたPodを全て停止することでReplicaSetに新しいイメージを作成させる。シンプルで高速だが障害を起こす可能性があり、ダウンタイムも避けられない。
Rolling Update: ある一定の期間、新旧バージョンの両方がリクエストを受けトラフィックを処理する。クライアント側が新旧どちらとも連携できることが重要になってくる。

maxUnavailableパラメータはローリングアップデート中に使用不可能になってもいいPodの最大数を指定する。絶対値もしくはパーセンテージで指定する。この値はローリングアップデートを進める速度にも関わってくる。

maxSurgeパラメータはロールアウト時にどのぐらいの追加リソースを作れるかを制御する。maxUnavailableを0、maxSurgeを20%に設定すると、レプリカ数を1.2倍に増やしてからレプリカの割合を旧0.8 新0.2へ更新する。maxSurgeを100%に設定するとブルーグリーンデプロイメントを行える。

minReadySecondsを使用するとPodが起動してから指定した時間後に次のアップデートに移る
spec:
  minReadySeconds: 60

タイムアウトを設定するにはprogressDeadlineSecondsを使用する
spec:
  progressDeadlineSeconds: 600

# ストレージソリューションとKubernetesの統合
セレクタのないService
dns-service.yaml
kind: Service
apiVersion: v1
metadata:
  name: external-database
spec:
  type: ExternalName
  externalName: "database.company.com
ExternalNameというタイプのServiceを作成すると、外部のDNS名を示すAレコードの代わりにCNAMEレコードを作成する。クラスタ内のアプリケーションがexternal-database.default.svc.cluster.localというホスト名をDNS名前解決すると、DNSプロトコルがdatabase.company.comに名前をエイリアスする。

IPアドレスのみ提供されている場合はサービスとエンドポイントを作成する必要がある
external-ip-service.yaml
kind: Service
apiVersion: v1
metadata:
  name: external-ip-database

external-ip-endpoints.yaml
kind: Endpoints
apiVersion: v1
metadata:
  name: external-ip-database
subsets:
  - addresses:
    - ip: 192.168.0.1
    ports:
    - port: 3306

Persistent Volumnの例
nfs-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: database
  labels:
    volume: my-volume
spec:
  capacity:
    storage: 1Gi
  nfs:
    server: 192.168.0.1
    path: "/exports"

PersistentVolumeClaimオブジェクトを使ってPersistentVolumnをPodから取得する
nfs-volume-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: database
spec:
  resources:
    requests:
      storage: 1Gi
  selector:
    matchLabels:
      volume: my-volume

StatefulSetはReplicaSetに似た複製されたPodのグループ。削除時やスケールダウン時に各レプリカはインデックスの数字が大きい順から削除される。
kubectl apply -f mongo-simple.yaml

StatefulSet作成後はDNSエントリを管理するヘッドレスなServiceも作る必要がある。
kubectl apply -f mongo-service.yaml
kubectl exec mongo-0 bash ping mongo-1.mongo

# 実用的なアプリケーションのデプロイ
Parse, Ghost, Redisのデプロイ方法のサンプル

Apr 15, 2018

Concentration is unnecessary


集中力はいらない」を読み終わりました。去年はDeep Work「大事なことに集中する」を読んだので、真逆とも言えるタイトルです。カバーには"だらだらするかうまくいく!"とまで書かれているので、Deep Workの著者が見たら破り捨てられないか心配です。集中力はいらないと言いつつ、こういう場面では必要というオチなのかなと思いきや、最後までいらないという論調で続きます。その代わり、"考える"ことが大事と書かれています。本の中で書かれている通り、考えているのではなく、反応しているだけの人が多いというのは自分にも当てはまっている気がして、ギクッとしました。

Apr 7, 2018

Kamameshi Makoto

My friend told me Makoto's kamameshi is good. Today,  I went to there for the first time. Ordered Kamameshi & Tonkatsu set. Usually, I don't like tonkatsu so much, but it was good. Though I ate in counter, raised floored seating area has cooking stoves. If you can eat there, kamameshi will be cooked in front of you. 

Makoto
Tonkatsu

Kani Kamameshi

Apr 6, 2018

Short circuit on Teradata


My colleague found that some queries on Teradata are improved by Short-circuit evaluation. This is common knowledge among software engineers, but DBA may not know it. I knew it short circuit, but I didn't know it is effective to sql.
For example, following query seems not bad and you may think everything is ok. (Please forget 'like any' since it is rewritten internally)

select
 *
from t1
where 
c1 like '%a0001%'
or c1 like '%a0002%'
or c1 like '%a0003%'
...
or c1 like '%a9999%'
;

By using short circuit, this query can be rewritten like this. 

select
 *
from t1
where 
c1 like '%a%' and 
(
 c1 like '%a0001%'
 or c1 like '%a0002%'
 or c1 like '%a0003%'
 ...
 or c1 like '%a9999%'
)
;

Of course, this rewrite isn't effective for all situations. It depends on the data characteristic. If all records of t1 contains a, it will be slower than before. In our case, the rewrite works well and it became 10-15x faster. Also, you need to know teradata optimizer can reorder evaluations. It means left most operation (c1 like '%a%') may be operated after right (c1 like '%a0001%' ... or c1 like '%a9999%') if optimizer judge it is the fastest order.

Apr 5, 2018

Presto CBO by Starburst

StarburstからCBOを実装したPresto (195e)が出ましたね。
リリースブログのグラフを見ると、良さしかないわけですが、みんな本家Prestoから乗り換えるのかが気になります。
Presto Cost-Based Optimizer rocks the TPC benchmarks!


もう少し詳しい情報はこちらのマニュアルに分かりやすく書かれています。今のところはHive Connectorのみで実装されているみたいですね。Teradata Connector (QueryGrid)ではいつ実装されるんだろう〜。わたし、気になります(千反田える)。
Cost based optimizations

そういえば最近知ったんですが、Starburstという名前で昔IBMからRBMSが出ていたんですね。1984〜1992年のプロジェクトなので、調べてみても今となっては当たり前のことが多く書かれていて当時何が新しかったのかが分からず...。こういうことは今から20年後とかにDeep Learningについて調べたら同じようなことを思う人がいるのかもしれません。「TensorFlowって名前のフレームワークがあったんだ。Pythonで使えて、GPUが使えて...えーと何が新しかったのだろう」みたいな。

Apr 4, 2018

Explain Viewer for Teradata

最近は空き時間にちょくちょくTeradata Japanに代々受け継がれて来たExplain Viewerというアプリケーションをメンテナンスしています。前に開発していた方々が退社してからは誰も改修していなかったようで、バージョンとしてはTD 13あたりでストップしていたようです(最新は16.20です)。幸いコアロジックはRubyで1000行ぐらいなので、比較的楽にメンテナンスできます。社内ブログにアップデートした旨を日本語で投稿したところ、他の国のメンバーからぜひ英語でポストしてくれ〜と来たので、書き直したところ何人か使ってくれているみたいで嬉しい。

Web Version
Electron Version



今までに修正した点としてはこんな感じです。

  • Teradataのバージョンアップ対応
  • Web部分のコードを書き直し
  • Web版からのruby.exeの廃止
  • Graphviz→Viz.jsへの変更
  • フォーマットをPNG→SVGへの変更
  • Electronバージョンの開発

一番悩んだのが内包されたRubyを廃止するかどうかです。コードにRubyを含めれば、何も設定せすに使えるというメリットはありますが、できれば避けたいなぁと。まあ誰もメンテナンスしてなかったぐらいだから自分が使いやすいように変えちゃえという気持ちで廃止しました(Electron版では残しています)。

Apr 2, 2018

From Jekyll To Blogger

GitHub Pages + Jekyllで動かしていた自分のサイトをBloggerに移行してみました。コードを載せる時はMarkdownがやっぱり良いのかもしれないけどなぁと後ろ髪を引かれながらも、改行や画像やリンクを載せる時の面倒くささが積み重なり、えいやで作業しました。カスタムドメインを変更する時に「ghs.google.com」に設定してくださいというメッセージが出ますが、「ghs.googlehosted.com」でないと上手くリダイレクトされないような...。みんなが使っているはてなやMediumを使わないあたりがひねくれていますね。

さて、先週から2018のF1がスタートしたので、予選から観戦しました。今年もHamiltonが優勝しそうな勢いを感じます。Australia GPはオーバーテイクがしづらいコースということで決勝中は途中寝落ちしたんですが、Vettelがバーチャルセーフティカー中にトップに立ったところからちょうど起きました。もちろんリスクを犯してピットに入らなかったFerrariの戦略が見事に当たったというのは、チームからすると良いことですが、こういう勝ち方が続くと、Hamiltonが一人勝ちするよりもつまらなくなってしまう気もしてしまいます。まあそんなに頻繁にあることではないと思っていますが。