Shogo's Blog

Feb 26, 2017 - 2 minute read - Comments - go golang redis

Redisを使ってユニークなIDを配布する

スケーラブルにIDを生成する方法として Twitterのsnowflakeが有名です。 1024台までスケールすることが出来ますが、各snowflakeのサーバにユニークなWoker IDを割り振る必要があります。 IDを振るためのサーバにIDを振るのが問題になるとは難しいですね。 各snowflakeサーバにIDを振る親玉Worker ID配布サーバを作るというアイデアはあったのですが、 Worker IDサーバの可用性を考えるのが大変で手を付けていませんでした。 最近になってWorker IDサーバとしてRedisを使い、ソート済みセット型で管理すれば楽できるのでは? と思いついたので、やってみたというお話です。 概要 レポジトリはこちらです。 shogo82148/yaraus 他のsnowflake-likeなID発番サーバの実装として katsubushiや sonyflakeなんていうのもあります。 これらのID発番サーバにRedisを使ってWorker IDを割り振るコマンドです。 Redis3.2以上推奨です。 使い方 Go製なのでgo getでインストールできます。 go get github.com/shogo82148/yaraus/cmd/yaraus # 1から1023までのIDが使えるようにRedisを初期化 $ yaraus init -min 1 -max 1023 # ユニークなIDが必要な処理を実行する $ yaraus run -- echo {} 2017/02/25 17:19:16 getting new id... 2017/02/25 17:19:16 client id: YourHostName-1488010756.738-1, id: 1 2017/02/25 17:19:16 sleep 2s for making sure that other generates which has same id expire.

Feb 25, 2017 - 1 minute read - Comments - rust rustlang go golang

Rust vs Go の終戦へ向けてPolyglotを作ってみた

「Golang Rust」とググると、関連項目は「Rust vs Go」のように GolangとRustが対立しているような項目ばかりです。 まあまあ、もっと仲良くやろうじゃないですか、ということで、 どうしたら仲良くなれるかを考えました。 Polyglotにして同じソースコードの中に閉じ込めてやれば、 そのうち仲良くなるのではないかと考え、 RustとGoのPloyglotを作ってみました。 結果 /*/*/ package main import "fmt" func main() { fmt.Print("Hello Go!!") _ = `*/*/fn main(){println!("Hello Rust!!");//` }/*/*/ package main import "fmt" func main() { fmt.Print("Hello Go!!") _ = `*/*/ fn main() { println!("Hello Rust!!"); //` } 仕組み 一番のポイントは最初の行の /*/*/ です。 RustもGoも/* */形式の複数行コメントに対応していますが、 Rustはネストに対応しており、Goはネストはできないという違いがあります。 この違いにより、Rustは/*/*/を/* /* /のように「二重にネストしたコメントの開始部分」として扱いますが、 Goは/* / */のように「/をコメントアウトしたもの」と見なします。 これにより2行目package main以降はGoには普通のコードに見えますが、 Rustからは単なるコメントとして認識されます。 次はGoからRustへの切り替えです。 Goではバッククオートで複数行文字列を定義できるので、その中にRustのコードを書きます。 この中ではバッククオートさえ使わなければ自由にRustのコードを書くことが出来るので、 あとはGoのコードだけ上手くコメントアウトされるよう調整すれば完成です。 せっかくなのでリンクしてみた GoからRustのコードを呼び出すサンプルコードを見つけたので、 せっかくなのでリンクしてみました。 medimatrix/rust-plus-golang main.

Feb 23, 2017 - 1 minute read - Comments - perl redis

WEB+DB PRESS Vol.97にPerlとRedisの記事を寄稿しました

昨年末にSongmuさんからお話を頂き、 WEB+DB PRESS Vol.97内の連載「第43回Perl Hackers Hub」に 「PerlでのRedis活用法」というタイトルで寄稿しました。 発売日は2月24日です。 内容 簡単に内容を紹介しておきます。 Perl使いではじめてRedisを使う人向けに書いたつもりです。 Redisの簡単な説明 Redisのインストール方と、Perlからの接続方法、そしてRedisの型の説明です。 記事の中でも紹介していますが、Redisはその豊富な型が特長です。 読者はきっとPerl使いだろうということで、Perlの型(Perlにも型はあるんだよ!!)と 比較しながら簡単に紹介しています。 Redisの応用例とCPANモジュールの紹介 Redisを使うとこんなことができるよ、という紹介です。 CPANで公開されているRedis関連のモジュールも合わせて紹介しています。 Redis自体の注意点 以前Redisを使ったサービスの運用に携わっていたのですが、 そのなかで実際に起きたことを元に、Redisの注意点について書きました。 さいわいサービスが停止するような事故にはありませんでしたが、 メトリックスを眺めながらエンジニア勢でヤバイヤバイ騒いでましたね・・・。 みなさんも気をつけて下さい。 執筆してみての感想 昔から文章を書くのにはだいぶ苦手意識があり、 今回の執筆も非常に苦労しました。 一文の前半を書いた時点で 「今から書こうとしている情報は本当に必要なのか」 「自分の記憶違いで間違った情報なのでは」と不安になり、 色々考えているうちに、何書こうとしてたのかわからなくなるんですよね。 まずは適当に書き上げて、後からちゃんと推敲しよう、 とは思いつつもなかなか進められず・・・。 スループットを上げたい。 細かい表現とかも気になってなかなか進まないので、 こういうの入れて頑張ろうと思います! VS Codeでtextlintを使って文章をチェックする gitbookで技術書を書く環境の構築手順 (執筆が進まないと、こういう環境構築に時間をかけてしまうのもよくないと思うんだ・・・) 余談 ところで、Vol.97と第43回ってどっちも素数ですね! 雑なプログラムを書いて調べてみたところ、 両方素数になるのはVol.83, 第29回以来、7回目(これも素数だ!)。 次はVol.101, 第47回です。 そのときのPerl Hackerは誰になるのでしょうか。楽しみですね! use warnings; use strict; sub is_prime { my $n = shift; return 0 if $n < 2; my $i = 2; while($i*$i<=$n) { return 0 if $n % $i == 0; $i++; } return 1; } my $i = 1; for my $n(1.

Feb 19, 2017 - 2 minute read - Comments - go golang

Go言語でコンパイル時フィボナッチ数列計算

整数の公式でフィボナッチ数列を求めるという記事を読んで、 「これコンパイル時ならGoでも簡単に計算できるのでは?」と思いやってみたメモ。 背景 みんな大好きフィボナッチ数列(要出典)。 漸化式で定義されているため、再帰やループを使って書くことが多いと思いますが、 閉じた式で書くことが知られています。 ただし、この一般式には無理数の演算が入るので、コンピュータで厳密に扱うことはできません。 ところが、さきほど紹介した記事で紹介された方法を使うと、整数の演算のみで実現できるそうです。 原理などはネタ元の記事を参照してもらうとして、 Python3では以下のように書けるらしいです。 def fib(n): return (4 << n*(3+n)) // ((4 << 2*n) - (2 << n) - 1) & ((2 << n) - 1) ある程度大きなフィボナッチ数を求める場合、 計算途中の値が非常に大きくなるため、多倍長整数が必要となります。 Python3は多倍長整数に組み込みで対応していますが、 Goではmath/bigパッケージを利用する必要があります。 なんか面倒だなGolangと思っていたのですが、 Better C - Go言語と整数 #golangを読んで、 「Goの定数には型がない(場合がある)」「任意の精度で計算してくれる」ということを知り、 「つまりコンパイル時に定数として計算すれば楽にいけるのでは!!」と考えたわけです。 結果 ちょっと複雑な式ですが、個々の演算自体はPython3もGoも変わらないので、 翻訳は簡単ですね。 package main import "fmt" const Fib0 = 1 // 0だけはうまくいかない const ( _ = (4 << (iota * (3 + iota))) / ((4 << (2 * iota)) - (2 << iota) - 1) & ((2 << iota) - 1) Fib1 Fib2 Fib3 Fib4 Fib5 Fib6 Fib7 Fib8 Fib9 Fib10 Fib11 Fib12 Fib13 Fib14 Fib15 Fib16 Fib17 Fib18 Fib19 Fib20 Fib21 ) func main() { fibs := []int{ Fib0, Fib1, Fib2, Fib3, Fib4, Fib5, Fib6, Fib7, Fib8, Fib9, Fib10, Fib11, Fib12, Fib13, Fib14, Fib15, Fib16, Fib17, Fib18, Fib19, Fib20, Fib21, } for i, fib := range fibs { fmt.

Feb 16, 2017 - 2 minute read - Comments - go golang

go-sql-proxyがcontextに対応しました

Go1.8ではdatabase/sqlのcontextサポートが入ります。 (きっと今日のGo 1.8 Release Partyで詳しく説明があるはず、たぶん) それにともないGo言語でSQLのトレースをするで紹介した shogo82148/go-sql-proxyでもcontextを扱えるようにしました。 Go1.8新機能のサポート Golang 1.8 でやってくる database/sql の変更点で mattnさんが紹介しているように、Go1.8ではdatabase/sqlにいくつか新機能が追加されます。 (mattnさんの対応が早すぎて、メソッド名とか微妙に変更が入っているので注意) 特に大きなのがcontextのサポートでしょう。以下のようなコードでクエリのキャンセルが可能になります。 ctx, cancel := context.WithCancel(context.Background()) go func() { // 1秒待ってからキャンセル time.Sleep(1 * time.Second) cancel() }() rows, err := db.QueryContext(ctx, "SELECT name FROM test where id = ?", id) if err != nil { log.Fatal(err) } go-sql-proxyでもcontext対応を行ったので、 proxyを経由した場合でも、キャンセルが可能になります。 (もちろん、originとなるドライバの対応も必要です) Go1.8ではcontextサポート以外にもいくつか新機能が追加される予定です。 これらについても、originとなるドライバが対応していれば、go-sql-proxy経由でも全く同じように扱えます。 contextとHookの関連付け contextにHookを関連付けて、一部のクエリにだけHookを付けることができるようになりました。 例えば以下のようなコードでctxに関連したクエリだけログを出力できます。 package main import ( "context" "database/sql" "github.com/shogo82148/go-sql-proxy" ) var tracer = proxy.

Jan 21, 2017 - 5 minute read - Comments - go golang

Go1.8のGraceful Shutdownとgo-gracedownの対応

Go1.8beta1が出た時に、Go1.8で追加される予定のGraceful Shutdownについて書く! とTwitterに書き込んで早1ヶ月。 この前の金曜日にGo1.8rc2がリリースされ、正式リリースも間近になってきて、 さすがに書かねばという気持ちになって来たので、がんばって検証してみます。 公式サポートで増える予定の機能 以前Go言語でGraceful Restartをするときに取りこぼしを少なくするで 紹介したようにshogo82148/go-gracedownというものを書きました。 あれから時は経ち、ついにGo1.8からはGraceful Shudownがbuild-inの機能として提供される予定です。 公式サポートが入ることによって、以下のような機能を使えるようになります。 HTTP/2のGraceful Shutdownができる HTTP/2ではGOAWAYフレームという接続を切ることを通知する機能があります。 Go1.8からはシャットダウン時にこのGOAWAYフレームを送ってくれるようになります。 GOAWAYフレームはサーバ側から任意のタイミングで送ることができ、 どこまで正常に処理できたかをクライアントに伝えられるという利点があります。 余談ですが、この機能はx/net/http2を利用している場合は動かないらしいです。 importしたときには動かないけどbundleしたときにだけ動く黒魔術が使われているためです。 覚えておいても今後絶対使うことはなさそう。というか使いたくない・・・。 contextが使える go-gracedownを作った頃は、contextはまだ標準パッケージに取り込まれていなかったので対応していませんでした。 (1.7のリリース時に対応を怠っていただけとも言える) net/httpのシャットダウンはもちろんcontextに対応しています。 これにより、Graceful Shutdownを中断して強制終了する、 ということが簡単にできるようになります。 公式サポートで変更になる予定の挙動 Keep-Aliveでのリクエストの挙動が少し変わります。 1.7以前のgo-gracedownでは、クライアントにKeep-Aliveが無効になったのを伝え、 クライアント側から接続を切るのを待つように実装してしました。 多少接続時間が延びたとしてもクライアント側でよくわからないエラーになるよりはマシだろ、との考えからです。 1.8からはシャットダウン時にIdle状態(TCP接続は有効だけど、リクエストは処理していない状態)な接続は切断されます。 内部で使っているServer.SetKeepAlivesEnabledの 挙動が変更になったためです。 Goの中の人的には「この挙動が原因で万が一トラブルになっても、クライアントがリトライしてくれるから大丈夫でしょ」とのことのようです。 サーバシャットダウン以外にもネットワークトラブル等でも接続は切れるので、 クライアント側で頑張ってというのは正論ですが、 どの程度エラーが増えるのかは気になるところです。 go-gracedownの対応 go-gracedownはGo1.8でコンパイルされたときはbuild-inの機能を直接使うようになります。 中身はほとんどがインターフェースの互換性を保つためのコードなので、 機能的なメリットは完全になくなってしまいました・・・。 HTTP/2サポートも問題なく動くはずです。 逆にパッケージの依存が増えること以外はデメリットはないともいえます。 Go1.7以下では今までの方法にフォールバックしてくれます。 というわけで、以下のような人には有用です。 深淵な理由でGo1.7以下しか使えない人 Go1.8とGo1.7以下のサポートがどうしても必要な人 Go1.8にアップグレードしたけど、graceful shutdownの処理を書き換えるのがめんどくさい人 ところで、環境が悪いときに性能を落としたり機能を制限することをフォールバック(fall back)というわけですが、 逆に環境が良いときに性能を上げたり機能を拡張することはなんていうんですかね? モデムでは通信環境が良いときに高速な通信方式に切り変えることを「フォールフォワード(fall forward)」というらしいです。 「Go1.8ではbild-inのGraceful Shutdownにフォールフォワードする」で使い方あってます? 使い方 Server.Shutdownを使う Go(その3) Advent Calendarの 最終日の記事でも扱ってますが改めて。 package main import ( "context" "fmt" "log" "net" "net/http" "os" "os/signal" "syscall" "github.

Jan 14, 2017 - 5 minute read - Comments - go golang

Re:golang の http.Client を速くする

先日mattnさんの記事を読みました。 golang の http.Client を速くする nettというパッケージを使って 名前解決の結果をキャッシュすることで、http.Clientを早くするというものです。 この記事に関して、ちょっと疑問に思ったことがあったので、検証してみました。 疑問 疑問に思ったのは以下の点です。 名前解決遅すぎでは? ベンチマークの結果を見ると5億ns(=500ms)ほど速度が改善しています。 3つのURLに対してリクエストを投げているので、初回を除く2回DNSのキャッシュがヒットし、 名前解決2回分の速度改善になるはずです。 と、いうことは、名前解決1回あたり250msかかっている計算になります。 googleのsearchは302でリダイレクトがかかるので、Client.Getの呼び出し1回あたり2回リクエストが飛ぶ、 ということを計算に入れても100msほどかかる計算です。 Google先生の謎テクノロジーによってかなりの最適化がされているはずですし、 ネットワークプロバイダのDNSキャッシュにヒットする可能性も高いでしょう。 名前解決程度にこんなに時間がかかっていたらスプラトゥーンが出来ない! (mattnさんがスプラトゥーンをプレイしているかは知らない) 2017/01/16追記: mattnさんはスプラトゥーンをプレイしていないそうです。残念。 あとスプラトゥーンしてません。。。 — mattn (@mattn_jp) 2017年1月14日 もちろん、ネットワークが混雑していたり、 モバイルネットワークを利用していたり、という可能性もありますが、 ちょっと不自然な印象を受けました。 Keep-Aliveされてるのでは? スキーマがhttpsになっているので、Google先生相手ならHTTP2で通信していてもおかしくありません。 HTTP2は基本的にドメイン毎にコネクションを1つだけ張って、それを使いまわします。 もし仮にHTTP1.1で通信していたとしても、http.ClientはデフォルトでKeep-Aliveが有効になっているので、 普通に使うとコネクションを再利用してくれます。 そういうわけで、名前解決以前にそもそもTCPのコネクション確立もスキップされている可能性が高いのでは? と思ったわけです。 この予想が正しければ、名前解決は初回リクエストでしか行われないので、ベンチマークに差はでないはずです。 HTTPリクエストの様子をトレースしてみる これらの疑問を解消するために、HTTPリクエストの様子をさらに詳細に解析してみることにしました。 DNSキャッシュなし版をトレースする Go1.7からnet/http/httptraceというパッケージが追加され、 名前解決やコネクション確立etcのタイミングにフックを仕込めるようになりました。 これを利用すれば各段階でどの程度時間がかかっているかが具体的に分かるはずです。 頑張って自前でフックを差し込んでもよいのですが、 deeeetさんのgo-httpstatという便利パッケージがあるので、 これをありがたく利用させていただきます。 go-httpstatを使うと時間計測を行うコードを簡単に差し込むことができます。 package main import ( "io" "io/ioutil" "log" "net/http" "time" "github.com/tcnksm/go-httpstat" ) var ( urls = []string{ "https://shogo82148.github.io/blog/2016/12/20/redis-fast-0-dot-19-released/", "https://shogo82148.github.io/blog/2016/12/15/leap-second-in-datetime-dot-pm/", "https://shogo82148.

Dec 20, 2016 - 1 minute read - Comments - perl reids

Redis::Fast 0.19リリースのお知らせ

Redis::Fast 0.19 をリリースしました。 主な変更点は以下の通りです。 reconnect_on_error オプションの追加 Sentinelのノード一覧が更新されない不具合の修正 IPv6の実験的サポート reconnect_on_error オプションの追加 @yoheimutaさんからのプルリクエストです。 今まではネットワークエラーが発生した時のみ再接続処理が走っていましたが、 Redisがエラーを返した場合にも再接続を行うようになります。 マスタースレーブ構成をしているときに、 何らかの原因によりRedis::Fastからのコネクションを維持したまま、 マスターがスレーブに降格してしまった場合に対処するための機能です。 以下のように設定することで、新しいマスターに再接続を行うことが可能になります。 my $r = Redis::Fast->new( reconnect => 1, # 0以上で再接続有効 reconnect_on_error => sub { my ($error, $ret, $command) = @_; if ($error =~/READONLY You can't write against a read only slave/) { return 1; # 再接続を行う。次の再接続まで最低1秒空ける } return -1; # 再接続は行わない }, ); Sentinelのノード一覧が更新されない不具合の修正 Redis::FastにはどれかひとつのSentinelノードに接続すると、 他のノードの情報を自動的に収集する機能があります。 この機能が最新のRedisでは動いていなかったので修正しました。 具体的にいつからなのかまでは追ってないのですが、 Redisのバージョン3.0.6から3.2.6の間のどこかで ノード一覧の形式が変わってしまったようです。 (最近Sentinelの話題を聞かないけど、みんな使ってるのかな・・・) IPv6の実験的サポート サーバの指定にIPv6のアドレスが使えるようになりました。 Redis::Fast->new(server => "[::1]:6379") のような指定ができます。

Dec 15, 2016 - 2 minute read - Comments - perl leapsecond

DateTime.pmにうるう秒の修正が入った話

こんにちは、DateTime.pm Watcherのいっちーです。 本日面白いパッチがDateTime.pmに取り込まれたので、ご紹介したいと思います。 そのpullreqがこちらです。Closedになっていますが、該当コミットはmasterに取り込まれています。 The leap second in 2012 was on 2012-07-01 not 2012-06-01. #48 per https://confluence.qps.nl/display/KBE/UTC+to+GPS+Time+Correction the leap second in 2012 was on 2012-07-01 not 2012-06-01. It’s is well known that leap seconds only occur directly before Jan 1st or July 1st. 適当な和訳「2012年に挿入されたうるう秒は2012年6月1日ではなく2012年7月1日です。よく知られているように、今までに挿入されたうるう秒は1月1日と7月1日の直前だけです。」 diff --git a/lib/DateTime/LeapSecond.pm b/lib/DateTime/LeapSecond.pm index 66e1b2b..4a38be2 100644 --- a/lib/DateTime/LeapSecond.pm +++ b/lib/DateTime/LeapSecond.pm @@ -108,7 +108,7 @@ sub _initialize { 1999 Jan. 1 +1 2006 Jan.

Nov 23, 2016 - 1 minute read - Comments - qrcode

Twitterの二次元コード問題と、QRコード・フレームQRの見分け方

先日Twitterの公式アプリがQRコード® (お店やお友達を簡単にフォローするために) の作成と読み取りに対応しました。 しかし、生成されるQRコードが標準規格に準拠していないため、 「他のリーダーで読めない」「法的に問題があるのでは?」等々の指摘が出ていました。 人事ながらTwitterさんのことが心配になったので少し調べてみました。 なお、僕は法律の専門家ではないため、本記事の正確性は保証できません。 あくまで個人的な見解なので、 実際にQRコード®を使用するさいは各自の判断でお願いします。 指摘ツイート Twitterが生成するQRコード、規格(JIS X 0510・ISO/IEC 18004)を大幅に逸脱しているので「QRコード®」を名乗ること自体に法的なリスクがある。 — 祥太(4/15レイフレ18 C19+20) (@shota_) 2016年11月17日 「デンソーウェーブは、JIS、ISOの規格に沿ったQRコードに限っては特許権を行使しませんが、規格を逸脱したQRコードについてはこの限りではございませんので、特許権を行使させていただくこともございます。」 (出典: https://t.co/SKXgBGSb8E ) — 祥太(4/15レイフレ18 C19+20) (@shota_) 2016年11月17日 明暗暗転で読み取らないという話を多数見かけますけど、そちらについては「ISO/IEC 18004からは逸脱」「JIS X 0510には準拠」(規格票7.3.8参照)という微妙な状況なのです。多分ISOには準拠しているのでアプリは悪くないと思います。 — 祥太(4/15レイフレ18 C19+20) (@shota_) 2016年11月17日 たしかに qrcode.comのFAQには 特許について以下の記述があります。 色を付けたりイラストを入れるような使い方をしても問題ありませんか? (中略) また、QRコードにイラストを重ねたりデザインを乗せるということは、QRコードの規格から外れ「QRコードではないもの」となってしまう可能性がございます。 デンソーウェーブは、JIS、ISOの規格に沿ったQRコードに限っては特許権を行使しませんが、規格を逸脱したQRコードについてはこの限りではございませんので、特許権を行使させていただくこともございます。 問題点 公式アプリの生成する二次元コードは以下のような問題があります。 データパターンの20%近くがアイコンで上書きされている 「アライメントパターン」がTwitterのロゴで欠けている 明暗暗転している(一応JISには沿っているらしい) 法的リスク以前に、 読み取り性能/互換性が劣化するので使わない方が無難でしょう。 自分のプロフィールのURL (僕の場合は https://twitter.com/shogo82148 )を QRコードに変換すれば公式アプリのリーダーでも読めるので、 こちらの方がオススメです。 QRコード関連の権利 特許 QRコード®のJIS規格JIS X 0510には、 関連する特許として特許第2938338号「二次元コード」があげられています。 ただし、特許の保護期間は20年なので、1994年に出願されたこの特許は2014年で消滅しています。 したがってこの特許を理由に訴えられることはなさそうです。