プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Unicode の全角マイナス問題にひっかかりました

SQL Server Management Studio (SSMS) を使って、 SQL Server を操作しているのですが、 SSMS ってそのままクエリを書くと Shift-JIS で保存されます。

で、いろいろあって、このクエリを Unicode (utf-8) に変換して管理しています。

ここで、 utf-8 への変換に nkf を使っていたのですが、全角マイナスが入っていると妙な文字に変換されることに気が付きました (なお、 iconv だと変換元のファイルの文字コードを指定する必要があって、それを避けたかったので、 nkf を使っています)。

このトラブルについて調べたので、せっかくなのでメモにしておきます。

なお、作業環境としては基本的に Windows 10 ですが、コマンドライン操作は wsl2 (Ubuntu 20.04) で行っています。

トラブルについて

例えば、全角マイナス1文字だけの Shift-JIS のファイルを用意して

f:id:junichim:20211014211449p:plain

mor@DESKTOP-DE7IL4F:~/tmp/jm$ xxd sample_zen_minus_sjis.txt
00000000: 817c 0d0a                                .|..
mor@DESKTOP-DE7IL4F:~/tmp/jm$

nkf を使って変換します。

mor@DESKTOP-DE7IL4F:~/tmp/jm$ nkf -w sample_zen_minus_sjis.txt > sample_zen_minus_utf8_w.txt

中身を見てみると

f:id:junichim:20211014211556p:plain

mor@DESKTOP-DE7IL4F:~/tmp/jm$ xxd sample_zen_minus_utf8_w.txt
00000000: e288 920d 0a                             .....
mor@DESKTOP-DE7IL4F:~/tmp/jm$

となります。微妙に半角マイナスっぽい感じになってますね(Unicode 表記だと U+2212 なので半角マイナスとは違いますね)。

検証のために、テキストエディタ(サクラエディタ)で、全角マイナスを入力してutf-8で保存すると、

f:id:junichim:20211014211746p:plain

mor@DESKTOP-DE7IL4F:~/tmp/jm$ xxd sample_zen_minus_utf8_editor.txt
00000000: efbc 8d0d 0a                             .....
mor@DESKTOP-DE7IL4F:~/tmp/jm$

となり、 Unicode 表記で U+FF0D となるので、先ほどの nkf による変換後のファイルの中身が全角マイナスとは違っていることがわかります。

さて、これはどういうことなんでしょうか?

原因と解決方法

これ、全然知らなかったのですが、下記の記事で書かれているように、有名な問題だったようです。

UTF-8における全角マイナスと全角チルダの問題(=いわゆる「波ダッシュ問題」) - 半径5メートル

この記事内からも参照されていますが、Wikipedia にも記載があります。

Unicode - Wikipedia

Wikipedia のほうには文字コードも載っているので、それと合わせると上記の変換結果と対応することがわかります。

結局、原因としては、仕様、ということのようです。

まあ、仕様なのはしょうがないのですが、一緒に解決法も載っていました(ありがたいです)。

nkf の場合は -w ではなく --ic と --oc を使って入力の文字コードを指定すればよいそうです。 なるほど。 Wikipedia の説明を踏まえると、 nkf の場合、 Shift-JIS から Unicode へ変換するのと CP932 から Unicode へ変換するので、変換先が違うんですね。

試してみます。

mor@DESKTOP-DE7IL4F:~/tmp/jm$ nkf --ic=cp932 --oc=utf8 sample_zen_minus_sjis.txt > sample_zen_minus_utf8_icoc.txt

ダンプしてみると

mor@DESKTOP-DE7IL4F:~/tmp/jm$ xxd sample_zen_minus_utf8_icoc.txt
00000000: efbc 8d0d 0a                             .....
mor@DESKTOP-DE7IL4F:~/tmp/jm$

おお、さっき、テキストエディタで保存した場合と一致しましたね。問題ないです。

ちなみに、iconv の場合も試しましたが、

mor@DESKTOP-DE7IL4F:~/tmp/jm$ iconv -f sjis -t utf8 sample_zen_minus_sjis.txt > sample_zen_minus_utf8_iconv.txt
mor@DESKTOP-DE7IL4F:~/tmp/jm$ xxd sample_zen_minus_utf8_iconv.txt
00000000: e288 920d 0a                             .....
mor@DESKTOP-DE7IL4F:~/tmp/jm$
mor@DESKTOP-DE7IL4F:~/tmp/jm$ iconv -f cp932 -t utf8 sample_zen_minus_sjis.txt > sample_zen_minus_utf8_iconv_cp932.txt
mor@DESKTOP-DE7IL4F:~/tmp/jm$ xxd sample_zen_minus_utf8_iconv_cp932.txt
00000000: efbc 8d0d 0a                             .....
mor@DESKTOP-DE7IL4F:~/tmp/jm$

となるように、入力ファイルの文字コードを sjis と指定すると nkf と同じ問題が起きますね(解決法も同じ)。

にしても、こんな問題があるなんて、やっぱり文字コードは怖いですね。

QNAP NAS の Web サーバーを無効化

QTS 5.0 にアップデートしたら、 Security Counselor というのが、セキュリティに関する注意を出してくれるようになりました。

で、今の設定だと Web サーバーが有効なので、無効にしたほうがよい、とのことです。

f:id:junichim:20211013093235p:plain

特に、 Webサーバー機能は使っていないので、無効にしたほうがよさそうですね。ということで、無効にしたので、その際のメモ書きです。

なお、対象機種は下記でした。

  • モデル: TS-231P
  • QTS: 5.0.0.1808

気になる点1

Web サーバーを無効化すると気になる点として、『ブラウザで GUI ログインできるのか?』というのがあります。

同じことを考える人はいるもので、ネットを調べてみると、同じような投稿がありました。

Disabling web server side-effects - QNAP NAS Community Forum

Do you need web server enabled to access QNAP web GUI? : qnap

このあたりを読んでみると、GUI ログインに問題は無いようですね。

気になる点2

じゃあ、いざ Web サーバーを無効化しようとすると、

f:id:junichim:20211012101342p:plain

という確認メッセージが表示されました。

いつくか App Center からアプリ(機能)をインストールしているものがあるので、どれが該当するか一目ではわかりません(QTS アップデートの際に、デフォルトでインストールされたりすることがあるので、自分でインストールした覚えがないのもあるのが困りものです)。

f:id:junichim:20211012101526p:plain

これについては、上記のインストール済みアプリの画面を付けて、サポートに問い合わせたところ、現在インストールされているアプリには該当するものがないとのことでした。

にしても、影響のあるアプリの一覧が欲しいところです。 > QNAP さん

無効化作業

ということで、無効化をやってみます。作業自体は簡単で、『コントロールパネル』の『アプリケーション』を選択し、『Webサーバー』を開きます。

f:id:junichim:20211013093712p:plain

『Webサーバーを有効にする』のチェックを外して、『適用』ボタンを押すと、先ほどの警告画面が表示されるので『OK』を選択します。

これでOKです。

確認

念のため、設定変更に使ったブラウザはそのままログインした状態で残して、別のブラウザでログインできるか試します。

f:id:junichim:20211014094037p:plain

問題なくログイン画面が表示されました。ログインもできますね。

次に、 Security Counselor を開いて、状態を更新してみます。

f:id:junichim:20211013094254p:plain

ちゃんと無効になってますね。

これで大丈夫そうです。

Windows 10 の iSCSI イニシエータで MC/S を利用する

新PC セットアップの続きです(終わらん・・・)。

iSCSI イニシエータの設定が完了し、ドライブとして使い始めました。ふと、iSCSI 接続を確認してみると、想定していたIPアドレスと異なるアドレスで接続されています。今回、 NIC 2枚刺しで iSCSI は専用の NIC を使おうと思っていたのですが、そうなっていませんでした。

これを機に、 iSCSI イニシエータの接続設定を見直したので、いろいろとメモっておきます。

最終的な形

下記のような形になることを想定しています。

NAS NIC1  ----- 仕事場LAN, 192.168.0.x ----- メインPC NIC1
NAS NIC2  ----- 直結, 192.168.2.x -------- メインPC NIC2

普段は、直結(以後、便宜上 iSCSI 専用ネットワークと呼びます)とした側の接続を使い、こちらにトラブルがあった際に、他方に切り替えて使えればと思います。

現状の設定

まずは設定中のものを確認します。『コントロールパネル』->『iSCSI イニシエータ』->『お気に入りのターゲット』タブ->『詳細』を開くと、

f:id:junichim:20211001120220p:plain

となります。iSCSI ターゲットは QNAP の TS-231P に設定しており、この機種は NIC が2枚あります。ここに表示されている IP アドレスは最終形として書いたように、仕事場のLANのネットワークアドレスになっており、 iSCSI 専用ネットワークのものではありません。

ちなみに、同じことは netstat でも確認できます。iSCSI のポート番号は 3260 なのでその接続を見ると、

C:\Users\mor>netstat -n

アクティブな接続

  プロトコル  ローカル アドレス      外部アドレス           状態
  TCP         127.0.0.1:49670        127.0.0.1:49671        ESTABLISHED
(中略)
  TCP         192.168.0.15:61656     192.168.0.7:3260       ESTABLISHED

となりました。

なので、再度接続を行ってみます。

設定変更

不要かもしれませんが、一度接続設定を削除してから、もう一度接続してみたいと思います。

現在の接続の解除

ファイル履歴を有効にした際の保存先が iSCSI 上のドライブなので、いったんファイル履歴を停止させます。

次に、ディスクの管理を開き、ドライブとしてマウントしているものを解除します。ドライブ名上で右クリックし、

f:id:junichim:20211001153210p:plain

『ドライブ文字とパスの変更』を選びます。

f:id:junichim:20211001153329p:plain

表示されたダイアログで、ドライブやパスを削除しておきます。

次に、一度 iSCSI 接続を切断します。

『お気に入りターゲット』タブを開き、接続中のターゲットを選択し、『削除』をクリックします。

f:id:junichim:20211001153437p:plain

次に、『ターゲット』タブを開き、現在接続中のターゲットを選択し、『切断』をクリックします。

f:id:junichim:20211001153458p:plain

確認を求められるので、

f:id:junichim:20211001153526p:plain

『はい』を選択します。

f:id:junichim:20211001153601p:plain

状態が非アクティブになりました。

最後に、『探索』タブを開き、

f:id:junichim:20211001153649p:plain

設定済みの『ターゲットを検索するポータル』を選択し、削除しておきます。

再接続

最初からもう一度設定します。

まず、『探索』タブを開き、『ポータルの探索』に iSCSI ターゲットのIPアドレスを入れます。

f:id:junichim:20211001153804p:plain

この時の IP アドレスは、iSCSI 専用ネットワーク側になる NAS の NIC2 のアドレスにします。続いて、『ポータルの探察』を実施します。

次に『ターゲット』タブに移ります。『検出されたターゲット』に iSCSI ターゲットが表示されていたら、これを選択し『接続』を押します。

f:id:junichim:20211001154009p:plain

『ターゲットへの接続』ダイアログが表示されるので、このまま『詳細設定』を押します。

f:id:junichim:20211001154026p:plain

詳細設定画面の『ターゲットポータル IP』に iSCSI 専用ネットワーク側の NAS NIC2 の IP アドレスを入力します。

f:id:junichim:20211001154107p:plain

このドロップダウンリストを見るとわかりますが、『探索』タブのターゲットポータルの探索で入力した IP アドレス(iSCSI 専用ネットワーク側のアドレス)とは別の、仕事場LAN側につながっている NAS NIC1 のIPアドレスも表示されています。このため、『規定値』のまま接続すると、リストの先頭側のアドレスに接続するんでしょうね、たぶん。

最初の接続は何も考えずに『規定値』でつなげたので、仕事場LAN側を使うことになったと思われます。便利っちゃ便利ですが、慣れてないと気付かないですね、この動作。

あと、 iSCSI ターゲット側では CHAP を有効にしているので、名前とパスワードも入力しておきます。

f:id:junichim:20211001154405p:plain

設定内容に問題がなければ、OKを押します。問題なく接続できれば、今度は

f:id:junichim:20211001154501p:plain

のようになり、接続先(iSCSI ターゲット)の IP アドレスが iSCSI 専用ネットワーク側のアドレス 192.168.2.2 になっていることが確認できます。

これで、 MC/S 化の準備が整いました。

冗長化について

次は冗長化です。 iSCSI の冗長化には、

  • MC/S, Multiple Connection per Session
  • MPIO, Multipath I/O

の2つの方法があるそうです。ですが、あとで詳しく述べますが、 Windows 10 の場合は MPIO が使えませんので、ここでは MC/S 一択です。

MC/S の設定

『ターゲット』タブを選択し、接続状態が『接続完了』になっているターゲットを選択し、

f:id:junichim:20211001154842p:plain

『プロパティ』を表示します。

f:id:junichim:20211001154905p:plain

表示された画面の『セッション』タブの一番下にある『MCS』を押します。

f:id:junichim:20211001155251p:plain

まず、接続を追加するため、『追加』を選択します。

f:id:junichim:20211001155513p:plain

引き続き『詳細設定』を押します。

f:id:junichim:20211001155612p:plain

『ターゲットポータル IP』に仕事場LAN側の NAS NIC1 のIPアドレスを指定し、CHAPの情報も入力しておきます。

次に、『MCSポリシー』を選択します。

f:id:junichim:20211001155400p:plain

普段は、 iSCSI 専用ネットワークで通信して、トラブル時のみ切り替えて接続したいので、『フェールオーバーのみ』としました。

f:id:junichim:20211001155749p:plain

フェールオーバーの場合は、一方(普段使うほう)がアクティブになり、他方(待機してるほう)がスタンバイになります。

設定内容に問題がなければ、各ダイアログで『OK』を押して設定を終了します(特に再起動など必要ありません)。

ちなみに、 NAS 側で接続状況を表示させると、こんな感じで2つの接続があることがわかります。

f:id:junichim:20211002001732p:plain

テスト

iSCSI 専用ネットワーク側の NAS NIC2 のネットワークケーブルを抜いてみます。MC/S のポリシーが『フェールオーバーのみ』になっているので、

f:id:junichim:20211001160505p:plain

のように、ステータスが自動的に『再接続中』になり、再接続処理を行ってくれました。

しばらくすると、ステータスが『接続完了』になります。もちろん、 iSCSI のドライブも問題なく使えます。

ただ、少し気になった点は、再接続が接続完了になるまで、若干タイムラグがありました。頻繁にディスクにアクセスするようなタイミングだとちょっと問題になるかもしれません。

あと、接続が復旧したあと、 MCS 設定を確認すると、アクティブとスタンバイが入れ替わってしまいました。

f:id:junichim:20211001160834p:plain

なので、自分で再度設定してやる必要があるかもしれません。

そう考えると、 MC/S のポリシーとしては『最小キューの深さ』とかを選択して、通常は負荷が少ないと思われる iSCSI 専用ネットワーク側を使うようにし、同時に仕事場LAN側の接続も生かしておくも、有効かもしれませんね(試してないです)。

参考:iSCSI の冗長化について

上記で少し触れましたが、 iSCSI 接続を冗長化する方法として、 MC/S のほかに MPIO というのもあるそうです。

どちらも iSCSI 利用時の接続を複数にすることで、冗長化や性能向上を行うという点では同じもののようです。違いは、 MC/S がその名の通り、1セッションでの接続を複数持つのに対し、MPIOは複数のセッションで接続を行う、というもののようです。

英語ですが下記の記事などを読むと何となくイメージがつかめます。

QNAP の設定記事(PDF)の前半に書いてあるものもイメージしやすかったです。

どちらを選べばよいかについては、上述の英語の記事とそこでも参照されている Microsoft の資料(Microsoft iSCSI Initiator Version 2.x Users Guide)にいくつか基準が載っています。下記に引用しておきます。

There are a number of things to consider when choosing to use MCS or Microsoft MPIO for multipathing.

  • If your configuration uses hardware iSCSI HBA then Microsoft MPIO should be used.
  • If your target does not support MCS then Microsoft MPIO should be used. Most iSCSI target arrays support Microsoft MPIO. Targets which support MCS include but are not limited to Network Appliance, EMC Celerra, and iStor
  • If your target does support MCS and you are using the Microsoft software initiator driver then MCS is the best option. There may be some exceptions where you desire a consistent management interface among multipathing solutions and already have other Microsoft MPIO solutions installed that may make Microsoft MPIO an alternate choice in this configuration.
  • If you need to specify different load balance policies for different LUNs then Microsoft MPIO should be used.
  • If you are using Windows XP or Windows Vista, MCS is the only option since Microsoft MPIO is only available with Windows Server SKUS.

Microsoft の資料(Microsoft iSCSI Initiator Version 2.x Users Guide)から引用

いろいろ条件はありますが、 MPIO の場合は、 iSCSI ターゲット単位ではなく、 LUN ごとに冗長化/ロードバランスのポリシーを変更できるので、そういうのが必要なら MPIO がよいそうです。

ちなみに、この MS の資料は、昔のもののためか、 MS の URL が見つかりません。まあ、タイトルをググれば、 PDF が落ちてるので簡単に入手できると思いますので、興味のある方は見てみると面白いと思います。

対応状況

MPIO と MC/S の対応状況もまとめておきます。

調べて驚いたのですが、WIndows 10 では MPIO は使えないようです(バグみたい)

QNAP の NAS のほうは対応しています(仕様の iSCSI のところに、 MPIO & MC/S の文言があります)。

なので、 iSCSI イニシエータとして Windows 10 を使う場合は、 MC/S 一択になりますね。