helloworlds

not a noun, it's a verb

【Golang】vim-goをインストールしてみた

ちょっと今年はだいたいvimgolangを学びたいと思っているので、 ひとまずvim-goをいれてみました!

vim-go

vim-goの詳細については、こちら

NeoBundle

vim-goを使用するのは、まずvimプラグインを導入するためのNeoBundleを設定する必要があります。

ここでは簡単にしか説明しないので、困ったらググってみましょう。 たくさん記事が出てくるかと思います。 既に導入済の方は、以下2つの見出しはスキップできます。

NeoBundleインストール

// .vimディレクトリへ移動
$ mkdir -p ~/.vim/bundle
$ git clone git://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim

.vimrcに記述

set nocompatible
filetype plugin indent off

if has('vim_starting')
  set runtimepath+=~/.vim/bundle/neobundle.vim
  call neobundle#rc(expand('~/.vim/bundle'))
endif 

NeoBundleFetch 'Shougo/neobundle.vim'

# 以下は必要に応じて追加
NeoBundle 'Shougo/unite.vim'
NeoBundle 'Shougo/neosnippet.vim'

filetype plugin indent on

上記を記述し保存したら、再度vimで適当なファイルを開いて:NeoBundleInstallを入力しましょう。

vim-goを記述

NeoBundle 'fatih/vim-go'

call neobundle#end() この記述の前に上記を追記します。

記述し保存したら再度適当なファイルを開いて、

:GoInstallBinaries

上記を入力し、インストールしたら完了です!

動作

動作はこちら確認します。

github.com

トラブルシューティング

  • 補完が動作しない... どうやらgocodeが原因のようです。 以下の手順で再度設定します。

  • go get -u github.com/nsf/gocode

  • gocode close
  • .vimrcに、let g:go_gocode_unimported_packages = 1 を追記。
  • gocode set unimported-packages true を実行。(インポートしてないパッケージも補完!)

以上です。

【SSL/TLS通信】Tips

SSL通信(SSL/TLS通信)

SSL通信とは、PKI (Public Key Infrastructure)認証方式の仕組みで実現されている、 公開鍵暗号方式を使ったインターネット上で安全にやり取りを行う公開基盤のことです。

三者機関である認証局(Certification Authority)が電子証明書を発行しています。

1度は絶対聞いたことがあるかと思うので、図は割愛します。

私がこれまで業務を行ってきた中でよくSSL通信をつかっていたのは、ログインや課金などのページが多かったと思います。 ネットサーフィンをしていると、そのような認証ページで使用されていることが多いでしょう。 いや、近年だと一般的にセキュリティ強化ですべての通信でSSL通信が使用されていることの方が多いかもしれません。

  1. ブラウザから https:// でリクエス
  2. 有効なSSLサーバ証明書があれば、WebサーバからブラウザにSSLサーバ証明書が送られる。 有効なSSLサーバ証明書がなければ、一時的に生成された公開鍵が送られる。
  3. ブラウザは(インストールされているルート認証で)SSLサーバ証明書を照合する。
  4. 照合されたらルート認証局の公開鍵でSSLサーバ証明書を復号化しWebサーバの公開鍵を取得する。
  5. ブラウザは共通鍵を作成し、Webサーバの公開鍵で共通鍵を暗号化し、Webサーバに送る。
  6. Webサーバは受け取った暗号メッセージを自身の秘密鍵で復号化し共通鍵として取り出す。
  7. これで共通鍵を使用したブラウザとWebサーバ間の暗号化通信が行われる。

SSLサーバ証明書

公開鍵と秘密鍵のbit数が長いほど、暗号の強度が高いと言える。 現在では2048bitの鍵長が多いでしょう。

たまにブラウザのアドレスバーで緑色になっているものがありますが、 それはEV SSLサーバ証明書という厳格に審査を行って発行されたSSLサーバ証明書なのです。

今回は短いですが、以上です。 SSL/TSL通信について詳しく知りたいのであれば、ググった方がはやいですww 大まかな流れだけ一旦頭に入れておけば大丈夫でしょう。 必要になった時に調べて対応できるくらいだと思います。

【AWS】DynamoDB Streams & Lambdaの関係

SQSのメッセージについて更新しました(記事下部に記載)

LambdaとSQS,DynamoDBの連携について、メモがてら実際試したことを書きます。

よく構成としてEC2を起動させて、SQSをポーリングしたりするかと思いますが、 近年だとLambdaのCLoudwatch Eventsなどを使用して定期的にSQSをポーリングさせたりしています。

日頃の運用として、DBに更新処理がかかったときに、その更新をトリガーとし なにか他の処理が行われるなんてことも大いにありそうですね。

AWSのサービスでいうと、DynamoDB Streamsだったり、 Kinesis Data Streamsだったりなんかを使用している方は多そうです。

そこで今回注目するのは、Lambdaの同時実行数やメモリサイズなどです。

DynamoDB Streams

DynamoDB Streamsを有効化していると、(DynamoDB Streamsは非同期で動作するので実際のテーブルのパフォーマンスに影響することはないそうです) アプリケーションはDynamoDB Streamsエンドポイントに接続してAPIをリクエストする必要があります。

このDynamoDB Streamsは、ストリームレコードというもので構成されていて、 ストリームレコード1件は、テーブル内の1件のデータ変更です。 このストリームレコードには、シーケンス番号が発行されます。

このストリームレコードの集合をシャードといいます。 シャードは、24時間後に自動的に削除されるそうですが、確かめてはいません。

細かい部分ではありますが、1つ気をつけることがあります。

DynamoDB Streamsを有効→無効→有効

シャードがなくなるかと思って、1度無効化にして再度有効化すると、 無効化する前のシャードは再び動き始めます。

また、このシャードは、Lambdaの同時実行数に関係してきます。

Lambdaの同時実行数 = DynamoDB Streamsシャード数

つまり、どんなにレコードに多く変更がかかってもシャード数自体が増えなければ、Lambdaの数は同等で、多く早くデータをさばきたくてもさばけないなんて状況になり得ます。

(※ シャード数は、DynamoDBテーブルのパーティション数と連動する!)

Lambdaのあれやこれ

上記で説明したLambdaとDynamoDB Streamsの連動でうまくいかいない時、 単純にパーティション数を増加させようとしますが、それはよく考慮する必要があります。

まず、最初にLmabdaをできるだけ高速化させることが重要です。

Lambdaの設定を見直してみましょう。

メモリ

デフォルトでは、128 MBで設定されていると思います。 この値は、MAX 3008 MB(およそ3 GB)まで上げることが可能です。

メモリを増加させることで、CPU性能の増加が期待できます。

しかし、単純にメモリサイズを増加させるだけはいかないことがわかりました。

Batchsize

テーブルに対してBatchsizeが設定されています。(AWSのコンソール、各Lambdaのページから確認可能) デフォルト値は、100だと思います。 これも増加させることで、Lambdaの1 Invocationあたりの処理レコード数を増加させることができます。

ここで、よく判断しないといけないことが...

メモリサイズの増加でDuration(呼び出しの結果として関数コードが実行を開始してから関数の実行が停止されるまでの実時間)の 低下をまず確認してからでないと、Batchsizeを上げても効果が得られないこと。

そして、Lambdaのペイロードサイズである 6 MB以内のレコードであること。 レコードのサイズが非常に高いとBatchsizeを上げても意味がない。

  • Lambdaの詳細をcliで確認
aws lambda list-event-source-mappings --function-name your-function \
    --profile profile-name --region your-region
  • Batchsizeを変更(uuidを上記コマンドで確認)
aws lambda update-event-source-mapping \
    --uuid "value" \
    --batch-size number \
    --profile profile-name --region your-region

そして最後のSQSです。

LambdaとSQSがポーリングしていて、尚且つレコード数が多い場合です。

DynamoDB Streamsから流れてきたレコードがLambdaへ渡り、SQSへいきますが、 SQSのドキュメントを確認すると、スタンダードキューの場合、キューあたり12万件までとなっています。

もし、大量(大量というのは100万件以上くらいかな?)のレコードに一気に変更がかかった場合、

-------更新範囲

パンクしないか?と、心配になってしまいます。

コチラ↑ SQSの公式ドキュメントと検証で理解しました。 SQSのメッセージは、ドキュメント上2つの種類がある(2つあると認識するかはその人次第です。ドキュメントを読む中で用語と仕組みをある程度完璧に認識して切り分けができている人は当たり前なことだと思います。私は読んでいて当初、インフライトメッセージというものが理解できずにいたためです)ということです。

ドキュメント上、メッセージとインフライトメッセージは別と考えましょう。

公式では、 「キューには最大 120,000 のインフライトメッセージが存在できます」と記載があります。

このインフライトメッセージというのは、 「キューから受信されたメッセージで可視性タイムアウト内にあって、まだキューから削除されていないメッセージ」 このことを指します。

よって、キューが持てるメッセージ数には制限がないという認識で問題ないです。

-------更新範囲

利用可能なメッセージがたーっくさん溜まっても、それと連動するサービスの処理速度をあげれば、問題なさそうでした。

40万件くらいたまりましたが、エラーなどは表示されず。

メッセージキューに含めるメッセージ数に制限はないと公式ドキュメントに書いてありますね。 ただ、転送中メッセージ数についてスタンダードキューで12万件という制限があるとも公式に記載があります。

これらを考慮して、3サービスをうまく活用していけたらと思います。 そして、一番重要なのは、よくドキュメントを読むことです。 勿論テストしたり、手を動かすことも大切ですが、ドキュメントに書いてある用語なり サービスの仕組みを理解することで、より具体的に調査やテストが可能だと思います。

【Python】勉強がてら簡単なWeb Scrapingやってみた

今年はPythonを少し勉強しようと思っていたので、簡単にできそうな「Web Scraping(Web スクレイピング)」のコードを書いてみた。 (勿論ググって参考参考しましたけど)

コマンドラインから

$ python3 filename http://domain/page

みたいにして任意のURLを引数にすると、そのページの画像を取得してくるというもの。 まあ、もうネットにありふれているけど、自分の勉強のためなので許して下さいw

pythonのヴァージョンは、3.5.0です。

今回使用したライブラリを以下です。

requests

PythonHTTPライブラリ。 パラメータを付与できたり、ヘッダーもカスタムしてPOSTしたりGETできる。

詳細はここ!!

BeautifulSoup4

HTMLやXMLの中身を解析して、任意の情報を取得するためのライブラリです。

詳細はここ!! 日本語はここ!!

lxml

XML(HTML)を扱う高速で便利なライブラリ

詳細はここ!! 日本語ならこの方の記事が良さそう!!

Pythonのライブラリなんて全然詳しくないので、新鮮に感じました。

そしてコードはこれだけ!

import requests
from bs4 import BeautifulSoup
import sys


args = sys.argv
URL = args[1]
images = []

soup = BeautifulSoup(requests.get(URL).content, 'lxml')

for link in soup.find_all("images"):
    if link.get("src").endswith(".jpg"):
        images.append(link.get("src"))
    elif link.get("src").endswith(".png"):
        images.append(link.get("src"))

for target in images:
    re = requests.get(target)
    with open ('img/' + target.split('/')[-1], 'wb') as f:
        f.write(re.content)

print("ok, successful!!")

任意のディレクトリでこのpythonファイルを作成し、同じ階層にimagesというディレクトリを作成します。 実行するとimagesフォルダ配下に、画像が取得されているというかんじ。

実に簡単でした。 ライブラリの細かい活用方法は、またおって何か開発するときにでも見てみようかと思います。

以上.

DBの高度な機能について

近頃DBにまわりの業務を担当することが多いので、DBの業務を行うにあたって 基本的なDBの機能について復習していきます。

物理サーバでもクラウドサービスを使用していても基本的な概念を精通していることが多いので、 機能ベースで確認していきます。

基本的な概念を抑えておけば、あとは各サービスの特徴を調べることが容易になったり 業務を行う上での近道になりそうです。

スケールアウト

そもそもスケールアウトとは、基本的に「仮想マシンの台数を増やす」ことを指します。 逆に「減らす」ことをスケールインといいます。

スケールアウトするための仕組みとして、主に以下の2つのワードをよく使用します。

レプリケーション

レプリケーションの目的としては、主に参照系処理をスケールアウトするということと覚えておきましょう。

具体的には、マスターサーバからスレーブサーバに対してDBの更新処理を送信し、 リアルタイムにコピーする機能です。

レプリケーションは、バックアップとは別であるということを意識します。 バックアップは定期的に行われるものだったりします。 そして、バックアップの場合は、異なる媒体(例えばAWSサービスのS3など)に転送されることが多いでしょう。 また、バックアップを使用する際というのは、リストアの作業が必要になります。

しかし、レプリケーションの場合は同様のシステム間で複製されることが多いのでしょう。 これは、なにか障害が起こった場合、マスターからスレーブへと切り替えサービス継続させるためです。

レプリケーションには、同期レプリケーション非同期レプリケーションがあります。

対象サーバへの同期が完了してから、次の処理を行います。 差分ログの転送までの同期と、差分ログの転送とデータへの適用までの同期などの厳密な区分がある。 つまり、基本的には完全なコピーがあるということです。

他のサーバにデータを送っている途中でも、次の処理を行います。 レスポンスの向上が見込めます。が、元のサーバがダウンするとデータの消失があるかもしれません。

また、レプリケーションには、マスターサーバが1台の場合や複数の場合などがあります。 企業やサービスなどによって異なるので、頭の片隅に「マスターサーバはいくつあるんだろう?」と、疑問に思うことを忘れないにしておくくらいでいいかと思います。

シャーディング(sharding)

よくAWSなんかさわっているとシャードなんてワードをよく目にします。 ドキュメント読んでる最中は、なんとなく理解しているつもりではいるのですが、 日が経つと「あれ?シャードってどんなんだっけか?」となります。

そこで色々調査した結果、シャードとは、 「1つのDBを分割して、複数に分散させて管理/運用すること」みたい。

Oracleさんに言わせるとこんなかんじ。

まあ、水平分割して負荷を下げられますよ、みたいなことなんだろうか。 レプリケーションでは参照系処理を行うサーバをスケールアウトさせるためでしたが、 「更新処理を行うサーバもスケールアウトさせたい」と思うことは普通のことです。

デメリットとしては、JOINなどが普通できない。 ただ、こんなものも用意されているようだからいいのかな?

最近は以下のようなかんじで、ほとんど気にしないで運用しているかと思う。

AWS Sharding Writeパターン

こちらが参考になります。

今ではAWSのようなクラウドサービスで仕組みだけ理解しておけば簡単に構成が組めてしまいますね〜。

次はもう少し内部の部分を確認します。

DBでは、I/Oがよくボトルネックになってくる場合があります。 これは過去記事で、DBMS内について復習している記事ですが、こちらにもSQLでI/Oを意識することが大切だと紹介しました。

o21o21.hatenablog.jp

このI/Oコストを少なくして高速に処理するための工夫がRDBMSにはあります。

データキャッシュ

これはよくご存知だと思います。 データキャッシュとは、ハードディスクから読み込まれたデータをメモリ上に保持しておくことで、 ハードディスクに再度アクセスすることを避けます。

パーティショニング

AWSでは、パーティションなんて言われます。 パーティショニングとは、実際は1つのテーブルを(指定した)ルールに基いて分離し格納する機能のことです。

簡単に言うと、アプリケーション側からは1つのテーブルに見えるので(SQLを変更することはなく) データが存在するパーティションだけを検索し応答速度を向上させることができる、みたいなかんじです笑

今度は、機能というより構成について簡単に確認してみます。

クラスタ

このワードもよくクラウドサービスを利用していると出てくるワードですね。 DB系のサービスでは、事ある毎にクラスター、インスタンス、.....などとワードが飛び交うと、 なにがどの機能を果たすのかわからなくなることがあります。わたしは笑

クラスタとは、複数のコンピュータを連結し、利用者や他のコンピュータに対して全体で1台のコンピュータであるように構成されているものです。

クラスタ内の代表的な構成としては、フェイルオーバーを意識したアクティブスタンバイ構成が挙げられます。 稼働しているサーバ(アクティブサーバ)に障害が起こると、スタンバイしているサーバ(スタンバイサーバ)のどれかが、 アクティブサーバに昇格します。

また、手動でアクティブサーバを切り替えることを、スイッチオーバーといいます。

以上、よく耳にするワードからDBをの機能を見直してみました。 基本的なことばかりですが、いろんなサービスで共通して使用されている概念だと思うので 少し用語(呼び方)が変わっても慌てず理解していけるようになれるといいです。

メモリの管理について

MMU

MMU(Memory Managemant Unit)とは、ハードウェアベースのメモリ管理ユニットです。 物理メモリと仮想メモリとのマッピングは、CPUに組み込めれているMMUで行われます。

TLM(Translation Lookaside Buffer)と呼ばれるバッファメモリもMMUの中にあります。 高速化のためのキャッシュとして活用されています。

スワップ

よくスワップという言葉を聞きますが、よく理解している人はどれくらいいるでしょう? 前のブログ「OS上のプロセスについて」でやったプロセスというものがあります。

プロセスはメモリが割当されないといけません。 まず仮想メモリの中から連続したメージ領域を確保しようとしますが、その仮想メモリと対応した物理メモリが確保できない場合があります。 スワップ(swap)とは、この時物理空間上の既に割り当てられているデータの一部をスワップ領域に追い出して場所を確保することです。 (※スワップアウト) 逆に、追い出したデータが必要になる場合ももちろんあります。 このデータが戻されることをスワップインといいます。

ページング

スワップの説明にでてきたページ領域ですが、この領域とは、 ページと呼ばれる固定サイズでメモリ空間を分割する単位のことです。

ハードディスクと物理メモリ間のページの出し入れをページングといいます。

一般的なページのサイズは、4KBでしょう。

NUMA

NUMA(Non-Uniform Memory Access)とは、非対称メモリアクセスのことです。

それはなんだというかんじです。

さきほど出てきたMMUがありましたね。 CPUに組み込まれたMMUは、サーバ上の全ての物理メモリにアクセスできます。 しかし、同一NUMAノード内の物理メモリには高速でアクセスできますが、 異なったNUMAノードにある物理メモリには低速になってしまう。

ということです。

もちろんPCの設計上、できるだけ同じNUMAノード内で処理されるようになっていますが、 大きなメモリを消費する場合は別のNUMAノードを使用せざるをえないです。

このNUMAですが、もう1つ覚えておきたいことがあります。

それは仮想サーバをさわるときです。

よくGUIで「仮想ソケット数×ソケットあたりのコア数」なんか設定するかと思います。 わたしも特に気にすることなく、デフォで設定してたりしますが、 仮に設定値を、2×4とか1×8とかに設定してなんの違いが?と思ったりします。

これはNUMAの概念をおさえておけば、わかることです。 よく仮想サーバのドキュメントを読むことをおすすめします。 どれもパフォーマンスに違いがあることを忘れないようにしましょう。

f:id:o21o21:20180327001006p:plain:w300

OS上のプロセスについて

プロセス

OS上での処理の最小単位がプロセスです。 すべての操作などはプロセスの単位で実行されると覚えておきましょう。

  • PID (プロセスID)
  • プログラムの実行命令コード
  • 変数など データ
  • ファイルの記述子
  • コンテキスト(CPUの状態)
  • スレッド

プロセスには親子関係があります。 親プロセスから子プロセスを生成することをforkといいます。 (※forkは英語で、分岐/枝分かれなどという意味を持ちます。)

このとき、子プロセスは親プロセスのメモリ空間をコピーして生成されます。 しかし、実はいきなりメモリ空間をコピーするのではなくリンク張って実際にプロセスの変更がかかったときにコピーが行われるのです。

プロセス同士は直接データの受け渡しはできません。 なので、プロセス間通信(例えば、$ <command> | <command> |...)という仕組みでやり取りをします。

lsコマンドやcatなどといった、よくコマンドラインで使用するコマンドも勿論プロセスです。

多くのプロセスは、3つの状態を持っています。

実行中」、「実行待ち」、「休止

私達がPCを操作しているときの多くは休止中になっているはずです。 まれにPCが重いと感じるときは、実行待ち状態のプロセスが多いためです。

コマンドラインでプロセスを強制的に終了させるには、killコマンドがありますし、 実行中のプロセスを停止させる手段としてCTRL+c(実はSIGINTというシグナルを送っている)なんかはよく使用するかと思います。

スレッド

スレッドはよく軽量プロセスライトウェイトプロセスなどと言われることがあるかと思います。 プロセスとの違いとは?という記事もよくみかけます。

スレッドとは、タスクの実行単位で、並列処理を目的としてプロトコルに複数作成されるものです。 なので、同じプロセス内にあるスレッドはメモリ空間を共有できます。

処理の流れ&仕組み

OSは複数の処理を並列処理するために、CPUの処理時間をms単位でタイムスライスします。 そして順次CPUリソースが割り当てれられていきます。

コンテキストが次々に実行待ち状態のプロセスに切り替えれていくことをコンテキストスイッチといいます。 コンテキストスイッチは、プロセスに与えられた時間も使い切るか、I/O待ちなどでCPUを手放したときに行われます。

CPUコア数が多いほど負荷が軽減できるでしょう。

これでメモリ上のスタックという領域にいき退避/復帰をします。

また、プロセスはどのような順番で実行されるのでしょうか?

この答えとしては、厳密にはOS(スケジューラーのアルゴリズム)によって違ってきますが、主な流れとしては以下になります。

これはスケジューラが実行可能キューから選択し、ディスパッチャーというCPUコアにに割り当てます。

こうした処理の流れを普段あんまり気にすることは少ないかと思います。

ですが、複数のバッチ処理やどうしても同じCPUコアで実行させたくない場合が出てきたら....

勿論プロセスの制御を行うことも可能です。

こうしたプロセスの割り当てを行うことをアフィニティーといいます。 論理プロセッサをグループ分けしてみましょう。

こうした設定はOSによって異なりますが、コマンドラインで設定したり確認できます。