uchan note

プログラミングや電子工作の話題を書きます

ReText を Windows 10 にインストールする

本記事は reST(reStructuredText) をライブプレビューできるエディター ReText を Windows にインストールする方法 を参考に、著者が試した記録だ。

注意点

  • 執筆時点の PyQt5 の最新版 PyQt5.5.1 は Python 3.4 向けにビルドされており、Python 3.5 系ではうまく動かない。
  • 参考記事と比べて環境変数の設定が少なくても動いた。
続きを読む

Kafka のトピック・パーティションの決め方を考察する

Apache Kafka は分散キューまたは pub/sub メッセージ配信システムとして使われるミドルウェアである。Kafka は pub/sub システムで一般的にある「トピック」に加えて、各トピックを分散処理のために分割する「パーティション」という機能を持っている。この記事では、どちらもメッセージを分類するという機能をもつ「トピック」と「パーティション」の使い分けを考察してみる。

トピック

トピックとは日本語で「話題」という意味がある。pub/sub システムでは、関連するメッセージを集める単位として使われる言葉らしい。筆者は pub/sub システムの一般的な概念をそんなによく知らないのではっきりしたことを言えないが、「アクセスログトピック」とか「システムログトピック」とか「気温と湿度のログトピック」というように、メッセージの種類ごとに分けるのがトピックだと考えている。

メッセージのパブリッシャ(送信側)とサブスクライバ(受信側)は、あるトピックを介してつながる。HTTP サーバは「アクセスログトピック」にログを出し、アクセスログを読みたいと思ったサブスクライバが「アクセスログトピック」に接続してログを読む。パブリッシャ、サブスクライバともに複数でも良く、「アクセスログ」というのをキーワードにしてゆるくつながる関係だ。

パーティション

これは一般の pub/sub システムにはない Kafka 独自の概念だ。パーティションはひとつのトピックを分割するもので、各パーティションはトピック内で一意の整数で区別される。例えば、「アクセスログトピック」はパーティション 0, 1, 2 を持つ、というように。パーティションの数は途中でも変えることができる。

Kafka では、サブスクライバを「コンシューマ(消費者)」と呼ぶ。論理的に一人の消費者を表す「コンシューマグループ」があり、あるコンシューマグループはひとつ以上の「コンシューマプロセス」から成り立つ。

Kafka は pub/sub システムであるので、あるトピックを複数のコンシューマグループが購読することができる。そしてここがポイントだが、あるコンシューマグループの中では、あるパーティションはどれかひとつのコンシューマプロセスに割り当てられる。ひとつのコンシューマプロセスが複数パーティションを担当することはあるが、ひとつのパーティションはひとつのコンシューマプロセスにしか割り当てられない。

パーティション割り当て戦略

パーティションは整数でしか区別されないので、アクセスログのホスト名ごとにパーティションを割り振る、というのは難しいし、おそらく Kafka では想定されていない使い方だ。そうではなく、ログの到着ごとにラウンドロビンパーティションに割り振るか、文字列のハッシュ値パーティション数で割った余りをパーティション ID とするか、もう少し頑張って、事前定義した文字列→整数の対応表にしたがって振り分けるか、という感じになるだろう。一応、文字列→整数の対応表を動的に作って共有するシステムを作れば、ホスト名ごとにパーティションを振り分けるのは不可能ではない。

ただ、現実的にはパーティション割り振りはラウンドロビンハッシュ値の余りでやるのがよさそうだ。つまり、あまり意味的な割り振りはせず、ただ負荷を分散させる目的でパーティションを使うということだ。なぜなら、Kafka 向けのサードパーティ製品は高度なパーティション割り振り戦略をサポートしていないことがあるからだ。例えば fluentd の Kafka 用プラグイン fluent-plugin-kafka では、パーティション割り振り戦略がラウンドロビンハッシュ値の余りかしか選べない。

トピックかパーティション

まとめると、意味的、またはログの形式が異なるものをトピックで分け、負荷分散の目的でパーティションを分けるのが良いだろう。負荷分散が目的なら、ログの割り振りはラウンドロビンで十分機能する。

ただ、パーティション分割を単なる負荷分散ではない目的で使わざるを得ない場合もある。

あるコンシューマプロセスが、特定の種類のログ、例えば「ホスト A」に関するアクセスログをすべて取得し、継続的に処理する必要があるとする。これは、ホスト A に関するアクセスのエラーレートを継続的に計算したい場合などに該当する。ホスト A に関するログが他のプロセスに流れてしまっては、正確なエラーレートを計算できないだろう。

この場合、ホスト A に関するアクセスログを別トピックとして切り出すか、ホスト名をハッシュ値の計算に含めるようにしなければならない。ホストごとにトピックを作っていたらトピックの数が増えすぎてしまうので、現実的にはすべてのアクセスログを単一トピックで扱い、ホスト名をハッシュ値の計算に含めることになると思う。

先ほど紹介した fluent-plugin-kafka は、パーティション振り分けのハッシュ値計算に使う文字列を指定できる。ログに partition_key という項目があればその値が使われ、ない場合には default_partition_key に設定した文字列が振り分けのキーとして使われる。もし、ホスト名とリモート IP の組み合わせでパーティションを振り分けたいという場合には、ホスト名とリモート IP を文字列結合した値を partition_key としてログに含めれば良い。

トピックは基本的に静的なものなので、アクセスログのホスト名のように、突然増えたりする場合には使いにくい。したがって、パーティションを意味的な割り振りに使う場面も出てくる。そんなとき、独自の割り振り戦略を考えるのではなく、文字列のハッシュ値の余りによってパーティションを決定するように設計するのが吉だろう。

Arduino に iPod の出力を繋ぐためのプリアンプ回路を実験してみる

少し前に プリアンプ回路を設計した ので、それを実装して実験してみた。

そもそもやりたかったのは、Arduino でデジタルエフェクタを作ることである。 そのために、交流である音声信号を、 1.65V を中心にして、なるべく 0V から 3.3V まで大きく振れる信号に変換したい。

動作実験

実装したプリアンプ回路の動作実験をした結果を紹介する。 回路に正弦波や音声信号を入力して、出力信号を観察した。

正弦波入力とプリアンプ出力

実装した回路に 1kHz の正弦波を入力して動作を観察してみた。

正弦波は "Tone Generator" などと呼ばれる iPhone アプリを使うと手軽に生成できる。 私は Audio Tone Genarator Lite を使った。

f:id:uchan_nos:20151223125856j:plain:w300

  • 上側:プリアンプ回路の出力信号(1V/div)
  • 下側:プリアンプ回路の入力信号(100mV/div、1kHz 正弦波)

下側のチャンネルは 1 メモリ 100mV 設定(100mV/div)なので、振幅は約 140mV である。 対して、上側のチャンネルは 1 メモリ 1V 設定(1V/div)なので、振幅は約 2.8V である。 きちんと増幅してくれているようで一安心だ。増幅率は約 20 倍。

プリアンプ回路の増幅率は可変抵抗で調整できるように作っている。 試しに増幅率をもっと上げてみると次のようになった。

f:id:uchan_nos:20151223131114j:plain:w300

プリアンプ回路で使っているオペアンプの電源が 3.3V なので、最大でも 3.3V の振幅までしか増幅ができない。 増幅率を上げすぎると、このように波形の上下が途切れてしまう。 Arduino で精度よくアナログ波形を読み取るには、ぎりぎり途切れないくらいの増幅率に設定するのがよい。

ちなみに、今回使った LMC6484AIN というオペアンプが "rail to rail" と呼ばれる特徴を持つ品種であるおかげで、電源電圧ぎりぎりまで増幅ができている。 rail to rail でないオペアンプでは電源電圧より低い電圧しか出力できないため、注意が必要だ。

音声信号入力とプリアンプ出力

今度は正弦波の代わりに iPod から実際の楽曲を入力し、増幅の様子を見てみる。

f:id:uchan_nos:20151223134615j:plain:w300

  • 上側:プリアンプ回路の出力信号(200mV/div)
  • 下側:プリアンプ回路の入力信号(10mV/div、iPod 音声信号)

下側のチャンネルは 1 メモリ 10mV 設定(10mV/div)なので、最大振幅は約 40mV である。 対して、上側のチャンネルは 1 メモリ 200mV 設定(200mV/div)なので、振幅は約 0.8V である。 画像では増幅されていることが分かりにくいが、きちんと 20 倍に増幅できている。

正弦波入力と DAC 出力

Arduino で AD 変換した結果をそのまま DA 変換するプログラムを作り、波形を見てみることにした。 Adruino Due は AD/DA ともに専用の回路を持っており、どちらも 12 ビットの精度で変換ができるので、 Arduino への入力信号と同じ波形が出力されると期待できる。

f:id:uchan_nos:20151223140240j:plain:w300

  • 上側:ArduinoDAC 出力信号(1V/div)
  • 下側:プリアンプ回路の入力信号(100mV/div、1kHz 正弦波)

下側のチャンネルは 1 メモリ 100mV 設定(100mV/div)なので、振幅は約 140mV である。 対して、上側のチャンネルは 1 メモリ 1V 設定(1V/div)なので、振幅は約 1.9V である。

増幅率は約 20 倍に設定してあるのでプリアンプ回路の出力は振幅 2.8V である。 なのに、DAC 出力が 1.9V になってしまうのはなぜだろうか。

Arduino Due の CPU である SAM3X8E の仕様書 を読むと答えが書いてあった。 DAC の出力電圧は電源電圧の 1/6 から 5/6 の範囲しか出ないらしい。

DAC 出力の振幅が入力の 2/3 になるということだから、2.8 × 2/3 ≒ 1.9 となり、観測結果は正しいようだ。

実装

ブレッドボード上に回路を実装した様子はこんな感じになった。

f:id:uchan_nos:20151223145850j:plain:w300

オリジナルサイズで表示

左側がプリアンプ回路、右側が Arduino Due の基板である。 プリアンプ回路の中央にある IC が、メインの部品となるオペアンプだ。

実装上の注意や、設計から一部変更した点などはまた今度書く予定。

Arduino に iPod の出力を繋ぐためのプリアンプ回路を設計してみる

注)Qiita で書いた記事 を引っ越してきました

ArduinoiPod の出力を精度よくデジタル変換したいなと思って、プリアンプ回路を設計してみた。対象は Arduino Due だけど、他の Arduino でも同じように使える回路になっているはず。

Arduino Due は 3.3V で動くので、AD 変換(アナログ-デジタル変換)の精度が最も良くなるのは 1.65V を中心に振幅が 1.65V の信号を入れたとき。しかし、iPod の出力の最大振幅は 1.0V 程度なので、AD 変換器の性能を引き出せない。

しかも、iPod のステレオミニプラグから取り出した音声信号は 0V を中心にして正負の電圧になる。それを ArduinoGND と A0 ピンに直接繋ぐと正側の信号しか取れないことになる。しかも Arduino の入力ピンに負電圧がかかるので Arduino を壊すかもしれない。

プリアンプの必要性

プリアンプ回路

ということで、中心電位を 1.65V に調整しつつ、振幅を増幅する回路を作る。それをプリアンプと呼ぶかどうかは良くわからないが、入力信号を調整するアンプという意味でそう呼ぶことにする。使った部品はすべて秋月電子通商で揃う。

プリアンプ回路図

回路図の左側がメインとなるアンプ回路だ。典型的な非反転増幅回路になっていて、増幅倍率を可変抵抗で調整できる。

右側が、Arduino から供給された 3.3V の電源から、その半分の 1.65V を作り出す回路だ。これもまたオペアンプの典型的な使い方で、ボルテージフォロワと呼ばれる。

回路図中のグランド記号がボルテージフォロワの出力に繋がっているのがポイントだ。電圧というのは相対的なもので、「グランド」を基準とすると ArduinoGND 端子は -1.65V、3.3V 電源端子は +1.65V になるというわけ。この回路のおかげで、アンプ回路の出力が Arduino からみて 1.65V を中心とした波形になる。

この設計の回路がちゃんと動くかは、後日検証する予定。

タッチパッドに手のひらが触れてカーソルが動くのを防止する

タイピング中に手のひらがタッチパッドに触れて、マウスカーソルが動いてしまったりクリックしてしまうことがある。それを防ぐために、タッチパッドの両端を無効化する方法を説明する。Ubuntu 15.04 で動作確認しているが、その他の Linux でも同様の方法が使えるはず。

続きを読む

【Ubuntu】ラップトップ PC の蓋を閉じてスリープさせる

LAVIE Direct HZ というラップトップ PC に Ubuntu 15.04 を入れて使っている。この PC は 13.3 型もの大きさがあるのに非常に軽く、筆者のお気に入りだ。ただ、残念なことに蓋を閉じてもスリープモードにならない問題があった。

※2017 年 1 月 29 日追記:Ubuntu 16.04 でも動作することを確認しました。

蓋を閉じてもスリープしない

蓋を開閉して dmesg を確認してみると、次のようなメッセージが出ることが確認できた。

f:id:uchan_nos:20200326090049p:plain

続きを読む