いぇいいぇい

ASP.NET、PHPを中心に書いています

管理画面系サイトにSPAは必要か?

先日管理画面系のサイトをリニューアルするにあたり、SPAを検討しました。その過程で何を検討し、どう判断したのかを書いてみたいと思います。

検討するサイト

まずは検討対象となるサイトについて説明したいと思います。 いわゆる管理画面サイトで、左側はサイドメニュー、右側はコンテンツエリアの2カラムレイアウト。サイドメニューの項目をクリックすると各ページのコンテンツが表示されます。 ヘッダー部分にはログイン情報があります。

コンテンツ・機能としては、以下のような物があります。

  • 項目リスト表示
  • 項目詳細表示
  • 項目編集
  • 項目追加
  • ログ表示
  • カレンダー・タイムテーブルによるタスク管理
  • 設定画面
  • ダッシュボード

バックエンドはASP.NET MVC。タスク管理機能など動的な部分はjQueryで実装しています。 SEOは必要ありません。モバイルアプリもありません。モバイルではPC版のレイアウトで操作できればOKなのでレスポンシブでもありません。

SPA、MPAの定義

SPA、MPAという言葉を多用するので、言葉の定義をします。

Single Page Application(SPA)
1つのページだけで構成されるサイト。ページ遷移がない。すべての動的コンテンツはAJAXで取得し、DOM更新する。ブラウザのヒストリーAPIを使って「ページ切り替えのようなこと」はできるが実際にはページ遷移していない。
Multi Page Application(MPA)
複数のページで構成されるサイト。ページ遷移を行う。ページの一部をAJAXなどを使って動的に更新することはできるがページ遷移するとページ全体を再表示することになる。SPAの対比のために使う。

リニューアルの要件

サイトをリニューアルするにあたり、以下の要件がありました。

  • デザインを新しく作り直す。(かっこいくておしゃれなやつ!)
  • タスク管理等の現在jQueryで実装している動的な部分も、ReactやVue等の最新のビューライブラリで書き直す。

SPAを検討した背景

ここ1,2年で、SPAの記事を目にすることが増えてきました。この時点ではSPAサイトを自分で作ったことはありませんでした。自分の中でSPAに対して抱いていた印象や知識は以下の様なことです。

  • ページ遷移がないので通信量が削減できる
  • ページ遷移がないので通信が発生せず、デスクトップアプリのようにキビキビ動く
  • バックエンドからUIロジックを排除できる
  • PCサイトとモバイルアプリで1つのバックエンドを使いまわしできる
  • JSファイルが大きくなるので初回ロードが遅いかも
  • SEOが不安なのでメディアサイトには向かないかも
  • それなりのフロント技術を求められるよ!

この中で一番魅力を感じたのは2番目のデスクトップアプリのようにキビキビ動くという点です。通常のWebサイトではページ遷移すると通信が発生するので、コンマ何秒かの待ち時間が発生します。これがなくなるのは地味だけど、でも体感できる差です。大きな差別化要因になると感じました。

「デスクトップアプリのようにキビキビ動くこと」は要件にはないですが、もしそれが実現できればそれに越したことはありません。そこでSPAについて詳しく検討することにしました。

検討したこと

以下、それぞれ検討したことと、その結果になります。プラス1なら☆(+1)、プラス2なら☆☆(+2)、マイナス1なら★としてランク付けしていきます。合算して☆が多ければ費用対効果があります。

検討にあたっては実際にAngular2でSPAサイトを構築してみました。

☆ページ共通部分を更新しなくていいのでその分高速化できる

SPAではサーバーは「データ」、フロントは「UI」と役割分担しますから、フロント側では必要な部分のみUI更新することができます。そうするとページヘッダーやナビゲーション部分はページ切り替え時には更新する必要がなくなりますからその分のレンダリングや通信コストが削減できます。これは正しいのでしょうか?

例えばログページから設定ページに移動した場合を考えてみます。

MPAの場合、

  1. ブラウザからページHTMLを要求
  2. サーバーでページ全体をレンダリングしてHTMLとして返す
  3. 返ってきたHTMLをブラウザで表示

SPAの場合、

  1. ブラウザから設定値をAJAXで要求
  2. サーバーで設定値をJSONで返す
  3. 返ってきたJSONをクライアントでDOM更新

上記を考えてみると、MPAはページ全体を送っているのに対して、SPAでは設定値だけを送っています。たしかに通信量は削減できそうですね。しかし体感できる程の差かどうかは、ケースによるのではないでしょうか。

今回のサイトの場合、ページ全体のHTMLは30KB程です。設定値のJSONが1KBだったとして、その差は29KBになります。29KB削減の効果は疑問です。モバイル環境なら大きいでしょうが、モバイルは想定していません。でも削減できるのはいいことですね。効果は小さいかもしれませんがプラス材料です。星ひとつ。

☆ページ遷移がないので通信が発生せず、デスクトップアプリのようにキビキビ動く

SPAはデスクトップアプリのようにキビキビ動くのが魅力です!この最大の利点を得るためにSPAにするといっても過言ではありません。 では管理画面をSPAにするとどうなるでしょうか?

前項の例を見てください。

あれ?どっちも通信発生していますね。SPAってページ遷移がないから早いんじゃなかったの??

通信が発生するということはMPAと同じく通信待ちが発生するということです。デスクトップアプリのようにキビキビ動きません。

SPAではキャッシュするから2回目以降はAJAXも要らないということでしょうか?ん?設定値をキャッシュする?それじゃ設定値が最新のものじゃないかもしれなくなるってことだからダメだよね。

設定ページ以外ならどうだろう。ログも最新じゃないと困るし、他も全部最新がいい。でも例えばログのページ送り操作のケースを考えると、クライアントサイドでキャッシュしてくれてもいいような気がする。その場合は通信がなくなるのでキビキビ動きますね。そっか、コンテンツによってキャッシュすべきかどうか違うんだ。で、キャッシュできないものはゼロ通信にできないと。

結局、SPAにしたからといって一律にゼロ通信にはできない。これじゃあデスクトップアプリにはなれない。当初期待していた目論見が崩れました。考えてみれば当たりまえの話ですが、大きな勘違いをしていたようです。

とりあえず、キャッシュできる場面ではキビキビ動くということで星ひとつ。

★初回は全ページのテンプレートを取得するため大きくなる

SPAはJSファイルに各ページのテンプレート、UIロジック、スタイル情報なども含めるため、ファイルサイズが大きくなりやすい。

初回表示が遅いってやつですね。ファイルを分割するなど工夫が必要になるかもしれません。マイナス星ひとつ

★★★ページキャッシュが使えない(戻る・進む問題)

これは実際に作ってみて気付いたことですが、SPAはブラウザのページキャッシュ機能が使えないんですね。

どういうことかというと、例えばログページから設定ページに移動した後、戻るした場合を考えてみます。

MPAの場合、

  1. ブラウザのページキャッシュからログページHTMLをロードして表示

SPAの場合、

  1. ブラウザの戻るイベントを受け、クライアントJSがログページのテンプレートをロードして表示
  2. クライアントJSがログデータをAJAXで要求
  3. サーバーがログデータをJSONで返す
  4. 返ってきたJSONをクライアントJSでDOM更新

MPAでは最終的なHTMLがブラウザのページキャッシュとしてローカルに残っていますから、それを表示するだけです。しかしSPAの場合はこのページキャッシュ機能が使えないため、自前ですべて賄う必要があります。対策としてはログ結果を自前でキャッシュしておき、戻る・進むの場合はキャッシュを参照するようにすることだと思いますが、MPAではブラウザがすべて面倒をみてくれる点と比べると気が重くなります。

これは当初想定していなかったデメリットです。管理画面系サイトはページ切り替えが多く、戻る・進むは普通に使います。マイナス星みっつ。

まとめ

他にも検討課題はあったと思いますが、この時点で今回のケースではSPAの採用を取りやめました。一番期待していたデスクトップアプリのようなUXが得られないと分かったからです。

おそらくSPAの使いどころというのは以下の点が判断条件になってくるのではないでしょうか。

  • サーバーからのデータ取得伴わない操作が多いか
  • サーバーからのデータ取得をキャッシュしやすいか

SPAにしろ、デスクトップアプリにしろ、データがリモートにある以上、通信待ちからは逃れられません。データをローカルに置けるというのはUI速度という面では利点です。データをリモートで一元管理できるというのもまた別の利点です。どちらも、ということは簡単ではありませんね。

ということで、以上となります。いかがでしたでしょうか?少しでも参考になれば幸いです。

Cloud Serviceがpagefile.sysを永続ディスクに配置するので固まる問題と回避法

Azure Cloud ServiceのVMでページングファイルがCドライブ(永続ストレージ)に配置されている件でトラブった経緯と調査、解決のために行ったことについて記載します。

運用環境

Azure Cloud Serviceで、ExtraSmallのVM2個で運用しています。osFamily、osVersionは未指定です。

OSはWindows Server 2012 R2 Datacenter。メモリは768MBです。

VMで処理が固まる

1年ほど運用してきましたが、最近処理が増えたのか、処理が途中で止まる現象が発生し出しました。

具体的には、

  • メモリを多く使うような箇所でログが途切れている
  • 物理メモリの使用率は常に100%近くで、仮想メモリも1~2GB使っている

ここで思ったのは、「ExtraSmallはそろそろきついか。。」、「もしかしてメモリリークしてる??」でした。メモリリークについてはメモリ使用量が増え続けてないので原因候補から外しました。

「じゃあ、性能不足か。予算が、、」、しかしメモリ使用量は物理、仮想合わせても3GB程度、仮想メモリは4GB確保しているので、まだ余裕はあるはず、この状況で処理が止まるなんてことあるだろうか?う~ん。

ここでふと、処理負荷時にディスク使用率が100%に張り付いているのを見つけました。HDDをそんなに酷使するような処理は行っていないので、なにがそんなに負荷を与えるの?と思いました。そういえばAzureのVMには永続ストレージと一時ストレージがあって、永続ストレージはものすごく遅いんだっけ、もしかして永続ストレージを使っているから重い?、とさらに調査してみることに。

VMにリモートデスクトップでログインしてパフォーマンスモニターで処理負荷時の様子を眺めました。すると以下のことがわかりました。

  • CPU負荷は問題ない
  • メモリ使用量もまだ余裕ある
  • Cドライブのディスク負荷がヤバイ

処理が止まる原因はCドライブの過負荷のようです。しかもCドライブに負荷をかけているのはpagefile.sys。

「そうか、物理メモリが少ないから常にページングファイルでガリガリやってる状態で、処理が立て込むとついには固まる、と。」

状況がわかってきました。

各ドライブの速度測定

一方で、VMには3つのドライブがあって、Cドライブ以外の負荷はまったくないような状況です。ここで疑問に思ったのはCドライブは永続ストレージ?それとも一時ストレージ?ということでした。もし永続ストレージなら改善の余地があるかもしれません。そこでネットを調べたところ、AzureのVMはDドライブが一時ストレージという記載がありますが、Cloud ServiceのVMにも当てはまるのか、情報が少なくはっきりしません。そこで実際に計測してみることにしました。

以下が実際のベンチマーク結果です。

Cドライブ

-----------------------------------------------------------------------
CrystalDiskMark 5.1.2 x64 (C) 2007-2016 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]
* KB = 1000 bytes, KiB = 1024 bytes

   Sequential Read (Q= 32,T= 1) :    43.511 MB/s
  Sequential Write (Q= 32,T= 1) :    56.066 MB/s
  Random Read 4KiB (Q= 32,T= 1) :     1.225 MB/s [   299.1 IOPS]
 Random Write 4KiB (Q= 32,T= 1) :     1.082 MB/s [   264.2 IOPS]
         Sequential Read (T= 1) :    74.436 MB/s
        Sequential Write (T= 1) :    68.354 MB/s
   Random Read 4KiB (Q= 1,T= 1) :     0.547 MB/s [   133.5 IOPS]
  Random Write 4KiB (Q= 1,T= 1) :     0.811 MB/s [   198.0 IOPS]

  Test : 500 MiB [C: 34.8% (6.9/20.0 GiB)] (x5)  [Interval=5 sec]
  Date : 2016/07/28 8:07:01
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)

Dドライブ

-----------------------------------------------------------------------
CrystalDiskMark 5.1.2 x64 (C) 2007-2016 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]
* KB = 1000 bytes, KiB = 1024 bytes

   Sequential Read (Q= 32,T= 1) :  1397.509 MB/s
  Sequential Write (Q= 32,T= 1) :   880.550 MB/s
  Random Read 4KiB (Q= 32,T= 1) :    68.634 MB/s [ 16756.3 IOPS]
 Random Write 4KiB (Q= 32,T= 1) :    92.339 MB/s [ 22543.7 IOPS]
         Sequential Read (T= 1) :  1697.640 MB/s
        Sequential Write (T= 1) :  1372.134 MB/s
   Random Read 4KiB (Q= 1,T= 1) :    27.629 MB/s [  6745.4 IOPS]
  Random Write 4KiB (Q= 1,T= 1) :    28.783 MB/s [  7027.1 IOPS]

  Test : 500 MiB [D: 34.0% (10.9/32.0 GiB)] (x5)  [Interval=5 sec]
  Date : 2016/07/28 8:13:56
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)

Eドライブ

-----------------------------------------------------------------------
CrystalDiskMark 5.1.2 x64 (C) 2007-2016 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]
* KB = 1000 bytes, KiB = 1024 bytes

   Sequential Read (Q= 32,T= 1) :   424.361 MB/s
  Sequential Write (Q= 32,T= 1) :   351.871 MB/s
  Random Read 4KiB (Q= 32,T= 1) :    78.930 MB/s [ 19270.0 IOPS]
 Random Write 4KiB (Q= 32,T= 1) :    71.282 MB/s [ 17402.8 IOPS]
         Sequential Read (T= 1) :   365.320 MB/s
        Sequential Write (T= 1) :   334.481 MB/s
   Random Read 4KiB (Q= 1,T= 1) :    13.171 MB/s [  3215.6 IOPS]
  Random Write 4KiB (Q= 1,T= 1) :    18.136 MB/s [  4427.7 IOPS]

  Test : 500 MiB [E: 41.4% (635.0/1534.9 MiB)] (x5)  [Interval=5 sec]
  Date : 2016/07/28 8:23:47
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)

この結果からDドライブが一時ストレージであることがわかりました。

なぜ永続ドライブに配置するのか

「そもそもなぜページングファイルを永続ストレージに配置するのか。ページングファイルは揮発性の情報だから、永続化する必要はないはずなのに。。単なるミス?それとももともとこのような仕様?」

MSに問い合わせてみようと思いましたが、インシデント代がもったない。。不具合という確証もないし。。

そこでMSDNフォーラムに質問してみました。

Cloud ServiceのExtraSmall VMで、pagefile.sysがCドライブに配置されている件

ページングファイルの場所をDドライブにしてみる

試しに手動にてページングファイルの場所をDドライブにして様子を見てみると、メモリ使用量は相変わらずですが、ディスク負荷はほぼ解消しました。

OK。これで解決しそうです。

ページングファイルの配置変更を自動化できる?

しかし、Cloud ServiceのVMはOSが自動更新されます。これによりページングファイルもCドライブに戻ってしまいます。OSが自動更新されてもページングファイルをDドライブにできるような方法はないものか。。

質問の回答ばかりに頼っていてもしょうがないので、自分で回避方法を探してみることにしました。

Cloud Servieにはスタートアップタスクという仕組みがあり、アプリケーション配置時にバッチスクリプトなどを実行することができます。既にNewRelicのインストールなどを行っていますし、ここでページングファイルの配置変更ができれば解決しそうです。

しかしページングファイルの設定変更にはOS再起動が必要です。できるのか。ネットで調べてみたところ、スタートアップタスクでOS再起動している人がいました。これはできるかも!やってみよう!

ページングファイルの配置変更スクリプト

やってみた結果、できました。

以下がページングファイルの配置変更スクリプトをスタートアップタスクとして登録する手順です。

1) ServiceDefinition.csdefにスタートアップタスクを登録します。

<ServiceDefinition ...>
  <WorkerRole ...>
    <Startup>
      <Task commandLine="changePagefileLoc.cmd" executionContext="elevated" taskType="simple"/>
    </Startup>
  </WorkerRole>
</ServiceDefinition>

2) changePagefileLoc.cmdをロールプロジェクト直下に追加します。

「出力ディレクトリにコピー」を「常にコピー」にします。 文字コードはASCII。

@echo off
DATE /T >> "%TEMP%\StartupLog.txt" 2>&1
TIME /T >> "%TEMP%\StartupLog.txt" 2>&1
ECHO Starting up changePagefileLoc.cmd. >> "%TEMP%\StartupLog.txt" 2>&1

PowerShell -ExecutionPolicy Unrestricted .\changePagefileLoc.ps1 >> "%TEMP%\StartupLog.txt" 2>&1
EXIT /B 0

3) changePagefileLoc.ps1をロールプロジェクト直下に追加します。

「出力ディレクトリにコピー」を「常にコピー」にします。 文字コードはUTF-8(BOM付き)。

Write-Output "==================="
Write-Output "Change pagefile location start"
$CurrentPageFile = Get-WmiObject -Query "select * from Win32_PageFileSetting"
Write-Output "C drive page file: $CurrentPageFile"
if ($CurrentPageFile -and $CurrentPageFile.Name.ToLower() -eq "c:\pagefile.sys") {
    $computer = Get-WmiObject Win32_computersystem -EnableAllPrivileges
    $computer.AutomaticManagedPagefile = $false
    $computer.Put()
    $CurrentPageFile.delete()

    Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{name="d:\pagefile.sys"; InitialSize = 0; MaximumSize = 0} -EnableAllPrivileges | Out-Null
    $PageFile = Get-WmiObject Win32_PageFileSetting -Filter "SettingID='pagefile.sys @ d:'"
    $PageFile.InitialSize = 4096
    $PageFile.MaximumSize = 4096
    [Void]$PageFile.Put()

    $PageFile = Get-WmiObject Win32_PageFileSetting -Filter "SettingID='pagefile.sys @ d:'"
    Write-Output "D drive page file: $PageFile"

    Write-Output "The computer will restart for the changes to take effect."
    Restart-Computer
}
Write-Host "Change pagefile location end"

まとめ

当面の回避策が見つかってよかったです。しかしなぜこのような仕様になっているのかは謎のままです。

ネットを探しても出てこない症状。可能性があるとすれば最近発生した不具合?、もし元々このような仕様だったとしたら、Cloud Serviceを使っている人はずっとこのような構成のOSを使わされていたということになります。

物理メモリが多いVMサイズではあまり問題になる状況はないかもしれませんが、ひとたびメモリ使用量が物理メモリを超えると、ページングによりCドライブが過負荷になり、しまいにはディスクアクセスエラーになり処理落ちするわけです。

ExtraSmallのように常にメモリ不足のような場合は致命的な問題です。まぁExtraSmallは開発・テスト用とされていますからね。素直に上のサイズ使えということですかね。

MSの人はこのことに気付いているのか、何か理由があってそうしているのか、聞いてみたいです。そういう窓口ってないんですかね。

gulp-watchで新規ファイルが認識しない問題が解決

以下のようにgulp-watchでファイル監視しているとき、ふと新規ファイルやリネームしたファイルが認識しないことに気づきました。

gulp.watch('./sass/**/*.scss', ['sass'])

調べて見たところ、解決策があったのでここで紹介します。

gulp-watchで新規ファイルを認識させる方法

gulp-watchではファイル監視にGazeを使っています。

Gazeでは、作業ディレクトリ(cwd)というパラメータがあります。規定値はprocess.cwd()となっており、最初の例では規定値が使われます。

どうもGazeではファイル監視に問題を抱えているようで、パラメータの指定の仕方にコツがいるようです。(参考:#41)

以下のようにcwdパラメータを指定して、監視パスから./をなくすと、新規ファイルでもうまく認識できるようになりました。

gulp.watch('sass/**/*.scss', { cwd: './' }, ['sass'])

これはGazeのバグかと思いますが、もう何年も放置されているようですね。。

GazeはGruntでも使われているようなので同じ問題があるかもしれませんね。

stackoverflow.com

github.com

複数のGitHubデプロイキーを同じマシンで使う方法

GitHubでは、デプロイキーは1つのリポジトリにのみ関連付けられます。ですので、通常はリポジトリ毎に異なるSSHキーを作成してデプロイキーとします。

ここで困るのが、同じマシンで複数のリポジトリをデプロイしたい場合です。例えば複数サービスを同じVPSに共存させる場合や、同じサービスだけど複数のリポジトリがある、という場合などです。

GitHubの場合、ホスト名とSSHキーを関連付けるために~/.ssh/configで以下のように指定しますが、単純に複数個指定してもうまくいきません。

Host github.com
    Hostname github.com
    User git
    IdentityFile ~/.ssh/id_proj1
Host github.com
    Hostname github.com
    User git
    IdentityFile ~/.ssh/id_proj2
> git clone git@github.com:tsu1980/proj2.git
ERROR: Repository not found.
fatal: The remote end hung up unexpectedly

同一マシンで複数デプロイキーを共存させる方法

そこで、以下のようにHostの値を分けて定義し、Git URLも同じ値を指定してやるとうまく動きます。

Host github.com-proj1
    Hostname github.com
    User git
    IdentityFile ~/.ssh/id_proj1
Host github.com-proj2
    Hostname github.com
    User git
    IdentityFile ~/.ssh/id_proj2
> git clone git@github.com-proj2:tsu1980/proj2.git
Initialized empty Git repository in /var/projects/proj2/.git/
remote: Counting objects: 833, done.
remote: Compressing objects: 100% (480/480), done.
remote: Total 833 (delta 400), reused 748 (delta 315), pack-reused 0
Receiving objects: 100% (833/833), 800.30 KiB | 523 KiB/s, done.
Resolving deltas: 100% (400/400), done.

Hostの値とGit URLのホスト名部分を一致させることがポイントです。この例ではgithub.com-proj2の部分になります。

cloneではなく既存リポジトリのURLを変更するにはgit remote set-urlを使ってください。

参考

Managing deploy keys | GitHub Developer Guide

superuser.com

Windows10でスタートアップフォルダを一発で開く方法

Windows10になってスタートメニューからスタートアップが消えました。今までスタートメニューから辿っていたのでとても困ります。スタートアップフォルダ自体は以前と同じ場所にあるのですが、それがとても深い階層にあるため、記憶だけではなかなか辿り着けません。スタートアップフォルダがどこにあるのか、簡単に開く方法はないのか、調べてみました。

一発でスタートアップフォルダを開く方法

  1. Windows+Eでエクスプローラーを起動します
  2. アドレスバーにshell:startupと入力してエンターキーを押します

f:id:sumi2:20160420122152p:plain

これでスタートアップフォルダを開けます。

ちなみに、すべてのユーザーのスタートアップフォルダを開くにはshell:common startupと打ちます。

hostsファイルが反映されない問題が解決

hostsファイルに書いたホスト名が反映されない問題で試した方法と原因、解決策についてまとめてみました。

症状

僕の場合はChromeでは名前解決できるのに、IEやpingではダメという状態になりました。

hostsファイルの中身

まずはhostsファイル(C:\Windows\System32\drivers\etc)の中身。

127.0.0.1       localhost abc1.localhost abc2.localhost abc3.localhost abc4.localhost abc5.localhost abc6.localhost abc7.localhost abc8.localhost abc9.localhost

全部で10個のホスト名を127.0.0.1に振り向けています。

このうち、abc9.localhostについてのみ、IEなどで名前解決できない状態になりました。

(本当は15個くらいあったのですが、表記上10個にしています。)

環境

  • Windows 10

名前解決の確認方法

名前解決ができているかどうかは、pingが通るかどうかで確認します。

ping abc.localhost

NGの場合はこうなります。

C:\WINDOWS\system32>ping abc9.localhost
ping 要求ではホスト abc9.localhost が見つかりませんでした。ホスト名を確認してもう一度実行してください。

OKの場合はこうなるはずです。

C:\WINDOWS\system32>ping abc9.localhost
abc9.localhost [127.0.0.1]に ping を送信しています 32 バイトのデータ:
127.0.0.1 からの応答: バイト数 =32 時間 <1ms TTL=128
...

1) DNSキャッシュのクリア

まずは定番のDNSキャッシュのクリアです。

ipconfig /flushdns
ipconfig /displaydns

しかし、状態は変わらずでした。

2) hostsファイルのアクセス権限

ファイルのアクセス権限をいじれば治ったという書き込みを見たので、ファイルにEveryoneフルコントロールのアクセス権限を追加してみました。 しかし、これも効果ありません。

セキュリティ上よくないのでアクセス権限は元に戻しておきます。

3) 1行あたりのホスト名制限

なんとWindowsのhostsファイルは1行あたりのホスト名に最大9個までという制限があるそうです。

superuser.com

確認してみると僕のhostsファイルには1行あたり10個以上のホスト名を記載していました。この情報に従って1行あたり9個までとなるようにhostsファイルを修正しました。

127.0.0.1       localhost abc1.localhost abc2.localhost abc3.localhost abc4.localhost abc5.localhost abc6.localhost abc7.localhost abc8.localhost
127.0.0.1       abc9.localhost

ただ、修正してもpingがまだ通りません。。

4) hostsファイルを1回削除してみる

何らかの理由により、hostsファイルの変更が検知できないような状態になっていると考え、一旦hostsファイルを削除してみることにしました。 もちろんファイルは別名のファイルに退避しておきます。具体的には以下の手順です。

cd C:\Windows\System32\drivers\etc
mv hosts hosts.bak
mv hosts.bak hosts

これでhostsファイルが正しく認識し、すべてのホスト名が名前解決できるようになりました。

まとめ

今回のケースでは1行に10個以上のホスト名を書いたことが原因でした。Chromeでは10個以上でも問題なく認識していたのですが、Chromeは独自にhostsファイルを読みに行っているのかもしれませんね。

また、hostsファイルの変更を検知させるためにファイルを一旦削除する方法が有効でした。これも1つの発見でした。

Evernote(Windows版)で書式なしでペーストする方法

Evernoteでコピーした文章をペーストすると、通常はリッチテキスト形式でペーストされます。リンクや色など書式付きになるわけですね。この動作はページ内容を見た目そのままで貼り付けたい場合はいいのですが、テキストだけを貼り付けたい場合は邪魔な動作になってしまいます。

今回はWindows版のEvernoteで、書式なしでペーストする方法と、それを既定の動作にする方法を掲載します。

書式なしでペーストするには

リッチテキスト形式ではなく、書式なしでペーストするには、[テキストとして貼り付け]コマンドを実行する方法があります。こうすることでプレーンテキストのみを貼り付けることができます。

メニューからの場合

Evernoteのメニューから、[編集]-[テキストとして貼り付け]を選びます。

ショートカットの場合

「Ctrl+Shift+V」キーを押します。

けど、貼り付けのショートカットキーといえば通常は「Ctrl+V」。Evernoteだけ異なるキーを押すというのはなんかイヤ。。

書式なしペーストを既定の動作にするには

もし「Ctrl+V」と「Ctrl+Shift+V」を置き換えることができれば、書式なしペーストを既定の動作にすることができます。しかし残念ながらEvernoteではショートカットキーのカスタマイズ機能は用意されていません。

そこで、AutoHotKeyという便利ツールを使います。AutoHotKeyはキー入力をフックして自由にカスタマイズすることができる常駐アプリです。今回のケースのようにアプリケーション側でキーカスタマイズ機能がない場合でもキー入力を置き換えることができます。

ただ導入には多少の手間がかかるのがデメリットですね。OS標準の機能としてくれてもいいような機能なんですけど。Evernoteを常用していて、どうしてもキーを置き換えたい!というひとはこの機会に導入しましょう。

導入方法は長くなるので省略し、スクリプトのみ紹介します。

;Swap Ctrl+V to Ctrl+Shift+V in Evernote
#IfWinActive, ahk_class ENMainFrame
    ^v::Send,^+v
#IfWinActive, ahk_class ENMainFrame
    ^+v::Send,^v

このスクリプトを追加することで、「Ctrl+V」と「Ctrl+Shift+V」を置き換えることができました。長く使うものだからこそストレスなく使えるようにしたいですよね。

autohotkey.com