割と普通なブログ

Microsoft Azure や ASP.NET、Java EE 系の話題を記載します

Azure Redis Cache を Java で利用する

Azure Redis Cache が日本でも利用可能になってしばらくたつが、確認のために Java から疎通を取ったので簡単にメモ。

使うまでの手順

Azure の新ポータル側 https://portal.azure.com にアクセスし、Data + Storage から Redis Cache を選択する。
f:id:waritohutsu:20150321191729j:plain

次に設定からアクセスポートを選択し「SSL によるアクセスのみ許可する」で「いいえ」を選択する。これは Redis の Java クライアントである Jedis が SSL 接続をサポートしていないためだ。
f:id:waritohutsu:20150321192134j:plain

管理ポータルの設定は以上なので、次は Java プロジェクトを作成し、pom.xml に以下を追記して Jedis の依存関係を解決する。

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.6.2</version>
        </dependency>

以下のコードを利用して Azure Redis Cache を利用できる。

package com.domain.redisclientproject;

import redis.clients.jedis.Jedis;

public class Main {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("<site name>.redis.cache.windows.net", 6379);
        jedis.auth("<管理ポータルから取得できるキー>");
        jedis.set("foo", "bar");
        String value = jedis.get("foo");
        System.out.println(value);
    }
}

疎通までとなるが、上記の様に簡単に利用することができるのが分かる。

Application Insight の Java モジュールの拡張ポイントを弄ってみる

前回の記事で Java アプリケーション向けに Application Insight を動作させる方法を紹介したが、こちらに対してイベント処理を追加することができる。拡張に利用することのできるクラスは以下の二つだ。

  • applicationinsights-core-0.9.1.jar に含まれる TelemetryModule.java
  • applicationinsights-web-0.9.1.jar に含まれる WebTelemetryModule.java

拡張ポイントについて

TelemetryModule.java と WebTelemetryModule.java はそれぞれインターフェースであり、コードは以下になる。

package com.microsoft.applicationinsights.extensibility;
import com.microsoft.applicationinsights.TelemetryConfiguration;
public abstract interface TelemetryModule
{
  public abstract void initialize(TelemetryConfiguration paramTelemetryConfiguration);
}
package com.microsoft.applicationinsights.web.extensibility.modules;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public abstract interface WebTelemetryModule
{
  public abstract void onBeginRequest(ServletRequest paramServletRequest, ServletResponse paramServletResponse);
  
  public abstract void onEndRequest(ServletRequest paramServletRequest, ServletResponse paramServletResponse);
}

眺めて頂けば察しがつくと思うが、モジュール初期化時、リクエスト前後で処理が追加できることが分かる。

拡張コードと設定

以下のクラスを作成した。

package com.mydomain.applicationinsightmodule;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.microsoft.applicationinsights.TelemetryConfiguration;
import com.microsoft.applicationinsights.extensibility.TelemetryModule;
import com.microsoft.applicationinsights.web.extensibility.modules.WebTelemetryModule;

public class MyTelemetryModule implements WebTelemetryModule, TelemetryModule {

	@Override
	public void initialize(TelemetryConfiguration initializer) {
		System.out.println("@@@@InstrumentationKey="
				+ initializer.getInstrumentationKey());
	}

	@Override
	public void onBeginRequest(ServletRequest paramServletRequest,
			ServletResponse paramServletResponse) {
		System.out
				.println("@@@@onBeginRequest at " + this.getClass().getName());
	}

	@Override
	public void onEndRequest(ServletRequest paramServletRequest,
			ServletResponse paramServletResponse) {
		System.out.println("@@@@onEndRequest at " + this.getClass().getName());
	}

}

さらに ApplicationInsights.xml に設定を追記した。

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<ApplicationInsights
	xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings"
	schemaVersion="2014-05-30">
	<InstrumentationKey><自分のキー>
	</InstrumentationKey>
	<ContextInitializers>
	</ContextInitializers>
	<TelemetryInitializers>
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer" />
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer" />
	</TelemetryInitializers>
	<TelemetryModules>
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.modules.WebRequestTrackingTelemetryModule" />
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule" />
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule" />
		<Add type="com.mydomain.applicationinsightmodule.MyTelemetryModule" />
	</TelemetryModules>
	<Channel>
		<!-- Setting DeveloperMode to true will enable immediate transmission of 
			the telemetry events, which can be helpful during the development process. 
			Make sure to turn this off on production servers due to performance considerations. -->
		<DeveloperMode>false</DeveloperMode>
	</Channel>
	<DisableTelemetry>false</DisableTelemetry>
</ApplicationInsights>

拡張が完了したので、Java Web アプリケーションを起動すると以下の様にログが出力されていることが確認できる(ホントは slf4j とか使った方がいいのは置いといて)。

情報: Starting Servlet Engine: Apache Tomcat/8.0.9
3 15, 2015 12:47:44 午後 org.apache.jasper.servlet.TldScanner scanJars
情報: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
@@@@InstrumentationKey=<自分のキー>
3 15, 2015 12:47:44 午後 org.apache.coyote.AbstractProtocol start
情報: Starting ProtocolHandler ["http-nio-8080"]
3 15, 2015 12:47:44 午後 org.apache.coyote.AbstractProtocol start
情報: Starting ProtocolHandler ["ajp-nio-8009"]
3 15, 2015 12:47:44 午後 org.apache.catalina.startup.Catalina start
情報: Server startup in 1987 ms
@@@@onBeginRequest at com.mydomain.applicationinsightmodule.MyTelemetryModule
@@@@onEndRequest at com.mydomain.applicationinsightmodule.MyTelemetryModule
@@@@onBeginRequest at com.mydomain.applicationinsightmodule.MyTelemetryModule
@@@@onEndRequest at com.mydomain.applicationinsightmodule.MyTelemetryModule

Application Insight を Java アプリケーションから利用する

アプリケーションのモニタリングやアラートを設定することが可能な Application InsightsJava からも利用可能になったのでさっそく試してみた。

利用するまでの流れ

まずは以下の様に Eclipse Plugin の Application Insight 機能をインストールする。
f:id:waritohutsu:20150315121832p:plain

次に、以下の様に Azure の新管理ポータルで Application Insight を新規に作成した後、setting - プロパティ から Instrumentation Key を取得する。
f:id:waritohutsu:20150315122236p:plain

次は Eclipse 上から Dynamic Java Web アプリケーションを作成し、右クリックメニューから Configure Application Insight を選択して Application Insight有効化する。この際、Instrumentation Key を求められるので管理ポータルから取得しておくのを忘れないこと。
f:id:waritohutsu:20150315122513p:plain

Application Insight 有効化すると、web.xml に以下の記載が追加されている。以下を見ると単なるサーブレットフィルタなので、Websites 等に配置せずとも動くことが推察できる。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="WebApp_ID" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>

	<filter>
		<filter-name>ApplicationInsightsWebFilter</filter-name>
		<filter-class>com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>ApplicationInsightsWebFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

更にソースフォルダに ApplicationInsights.xml が配置されており、以下の記載がされている。こちらで Application Insight を構成する情報が設定されていることが分かる(TelemetryInitializers タグにクラスを追加すると何かしてくれそうな気もする)。

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<ApplicationInsights
	xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings"
	schemaVersion="2014-05-30">
	<InstrumentationKey><自分のキーが書いてある>
	</InstrumentationKey>
	<ContextInitializers>
	</ContextInitializers>
	<TelemetryInitializers>
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer" />
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer" />
	</TelemetryInitializers>
	<TelemetryModules>
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.modules.WebRequestTrackingTelemetryModule" />
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule" />
		<Add
			type="com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule" />
	</TelemetryModules>
	<Channel>
		<!-- Setting DeveloperMode to true will enable immediate transmission of 
			the telemetry events, which can be helpful during the development process. 
			Make sure to turn this off on production servers due to performance considerations. -->
		<DeveloperMode>false</DeveloperMode>
	</Channel>
	<DisableTelemetry>false</DisableTelemetry>
</ApplicationInsights>

この時点でも動作はするが Application Insight のクイックスタートの画面から以下の JavaScript が取得できるので、こちらを JSP 画面 or JSF 画面等の監視をしたいページに張り付ける。

<!--
ご使用のアプリケーションに関するエンド ユーザー利用状況分析を収集するには、
追跡するページごとに以下のスクリプトを挿入してください。
このコードを、</head> 終了タグの直前に、
他のスクリプトより前の位置に配置します。最初のデータは、数秒後に
自動的に表示されます。
-->
<script type="text/javascript">
    var appInsights=window.appInsights||function(config){
        function s(config){t[config]=function(){var i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},r=document,f=window,e="script",o=r.createElement(e),i,u;for(o.src=config.url||"//az416426.vo.msecnd.net/scripts/a/ai.0.js",r.getElementsByTagName(e)[0].parentNode.appendChild(o),t.cookie=r.cookie,t.queue=[],i=["Event","Exception","Metric","PageView","Trace"];i.length;)s("track"+i.pop());return config.disableExceptionTracking||(i="onerror",s("_"+i),u=f[i],f[i]=function(config,r,f,e,o){var s=u&&u(config,r,f,e,o);return s!==!0&&t["_"+i](config,r,f,e,o),s}),t
    }({
        instrumentationKey:"<自分のキーを利用する>"
    });
    
    window.appInsights=appInsights;
    appInsights.trackPageView();
</script>

上記を利用してローカル等で Tomcat を起動して動作を確認すると、無事情報が取得できていることが分かる。
f:id:waritohutsu:20150315123649p:plain

WindowsAzureToolkitForEclipseWithJava / StarterKit / CSPackAntTask を修正する

Microsoft Azure のクラウドサービス向けの Eclipse Plugin として Windows Azure Toolkit For Eclipse With Java があるのはご存知だと思う(未だに Windows Azure なのは置いといて)。こちらを利用して Eclipse 上からリモートデスクトップ、セッションアフィニティ、デプロイするロース数の設定等が可能だ。

ずいぶん進化が進んだもので、JBoss AS, Tomcat, Jetty はもちろん WebSphere も対応したそうだが、The Azure Toolkit for Eclipse now Includes WebSphere Liberty and Application InsightsIBM 社の WebSphere にも対応したらしいが、試してみたところうまく動かなかったので自身でプラグインをリコンパイルして確認をしてみた。ノウハウを死蔵してもしかたないので、今回は Windows Azure Toolkit For Eclipse With Java のリコンパイルの TIPS を紹介する。

修正箇所/内容

今回私が修正した個所は WindowsAzureToolkitForEclipseWithJava / StarterKit / CSPackAntTask であり、Eclipse プロジェクト内に .cspack.jar という隠しファイル名で格納されている個所だ。ソースコードを確認したところpackage.xml 設定ファイルから *.cspkg ファイルを作成する処理を担っている様だ。
こちらに対して「*.cspkg を作成する際の引数をログとして出力する処理」を追加する。

まずは Github から以下の定番コマンドでソースコードを取得する。

>git clone https://github.com/MSOpenTech/WindowsAzureToolkitForEclipseWithJava.git

上記に CSPackAntTask が含まれているので、Eclipse の既存プロジェクトのインポートから WindowsAzureToolkitForEclipseWithJava\StarterKit\CSPackAntTask を選択する。

ソースコードをインポート後、ビルドが通らないがどうやら org.apache.ant と com.microsoft.azure が足りないようなので、以下の pom.xml をダミーで作成して mvn eclipse:eclipse で依存 jar を取得する*1

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.microsoft.azure</groupId>
	<version>0.7.0</version>
	<artifactId>azure-cspack-anttask</artifactId>
	<packaging>jar</packaging>

	<dependencies>
		<dependency>
			<groupId>org.apache.ant</groupId>
			<artifactId>ant</artifactId>
			<version>1.8.2</version>
		</dependency>
		<dependency>
			<groupId>com.microsoft.azure</groupId>
			<artifactId>azure-storage</artifactId>
			<version>2.0.0</version>
		</dependency>
	</dependencies>
</project>

次に *.cspack ファイル作成時のコマンド引数をログとして出力する処理を追加するため com.microsoftopentechnologies.windowsazure.tools.build.WindowsAzurePackage.java に以下の様に処理を追加する。ソースコードを見ればわかるが、中身に cspack.exe を利用している様だ。

	public void execute() throws BuildException {
		// <中略>

		// Run cspack.exe
		this.log("Starting package generation...");
		try {
			if (getSdkDir() != null) {
				// Get cspack.exe cmd-line
				List<String> csPackCmdLine = this.createCSPackCommandLine();

				//追加処理ここから
 				for (int i = 1; i < csPackCmdLine.size(); i++) {
					this.log("arg" + i + ": " + csPackCmdLine.get(i));
				}
				//追加処理ここまで

				this.runCommandLine(csPackCmdLine);
			} else {
				throw new IllegalArgumentException(
						"Azure SDK not found, cannot build non-CTP package");
			}
		} catch (Exception e) {
			reportBuildError(e);
		}

修正後、Ant を利用して備え付けの build.xml をたたくことで Eclipse プロジェクト内の jar フォルダに .cspack.jar が作成される。この時点での Eclipse プロジェクトの Package Explorer は以下のようになる。

最後に、CSPackAntTask\jar\.cspack.jar フォルダを Azure Eclipse プロジェクト内に含まれる .cspack.jar に上書きしてクラウドサービス上へのデプロイを試すと以下の様に追加処理のログが出力されている*2

Buildfile: D:\opt\workspace\HelloAzure\package.xml

checkResetScript:

resetEmulator:

waitForReset:

createwapackage:
       [mkdir] Created dir: D:\opt\workspace\HelloAzure\deploy
      [delete] Deleting directory D:\opt\workspace\HelloAzure\deploy.old
[windowsazurepackage] Verified attributes.
[windowsazurepackage] Role "WorkerRole1": Verifying the approot "D:\opt\workspace\HelloAzure\WorkerRole1\approot"
[windowsazurepackage] Role "WorkerRole1": Importing components...
[windowsazurepackage] 	Imported as 'jdk1.8.0_25' from "C:\Program Files\Java\jdk1.8.0_25"
[windowsazurepackage] 	Imported as 'jboss-as-7.1.1.Final.zip' from "D:\opt\jboss\jboss-as-7.1.1.Final"
[windowsazurepackage] Role "WorkerRole1": Finished importing components
[windowsazurepackage] Role "WorkerRole1": Generating component deployment script...
[windowsazurepackage] Role "WorkerRole1": Created internal startup script
[windowsazurepackage] Starting package generation...
[windowsazurepackage] arg1: D:\opt\workspace\HelloAzure\ServiceDefinition.csdef
[windowsazurepackage] arg2: /role:WorkerRole1;D:\opt\workspace\HelloAzure\WorkerRole1\approot
[windowsazurepackage] arg3: /rolePropertiesFile:WorkerRole1;D:\opt\workspace\HelloAzure\.rolePropertiesOS3
[windowsazurepackage] arg4: /out:D:\opt\workspace\HelloAzure\deploy\WindowsAzurePackage.cspkg
[windowsazurepackage] Executing '[C:\Program Files\Microsoft SDKs\Azure\.NET SDK\v2.5\bin\cspack.exe, D:\opt\workspace\HelloAzure\ServiceDefinition.csdef, /role:WorkerRole1;D:\opt\workspace\HelloAzure\WorkerRole1\approot, /rolePropertiesFile:WorkerRole1;D:\opt\workspace\HelloAzure\.rolePropertiesOS3, /out:D:\opt\workspace\HelloAzure\deploy\WindowsAzurePackage.cspkg]'...
[windowsazurepackage] Process started
[windowsazurepackage] Microsoft(R) Azure(TM) Packaging Tool version 2.5.0.0
[windowsazurepackage] for Microsoft(R) .NET Framework 4.0
[windowsazurepackage] Copyright c Microsoft Corporation. All rights reserved.
[windowsazurepackage] D:\opt\workspace\HelloAzure\ServiceDefinition.csdef: Warning  CloudServices040 : The 'schemaVersion' attribute is unspecified. Please set the attribute to avoid this warning.

このように必要な場合はソースを修正して動作を確認することがご理解いただけたと思う。

*1:ここの pom.xml は公開してほしいところ

*2: Executing 行の ... 部分が気になったので処理を追加したが、特に見切れてたのはなさそう

Microsoft Azure の Premium Storage を利用してみた

Azure: Premium Storage, RemoteApp, SQL Database Update, Live Media Streaming, Search and More の記事で2014年12月に発表された Premium Storage だが、漸く利用可能になったのでさっそく検証してみた。
Premium Storage を利用することにより「仮想マシンの IOPS がイマチイなんだよねぇ…」というケースの解として提案可能になるが、2015年2月15日現在はプレビュー期間中であり日本リージョンでは利用できない(West US, East US 2, West Europe で利用可能)点に注意が必要だ。

最初に今回のまとめ

Premium Storage: High-Performance Storage for Azure Virtual Machine Workloads に詳しい記載があるが、注意が必要な点は以下になる。

  • 2015年2月15日現在、プレビュー期間中であり日本リージョンでは利用できない(West US, East US 2, West Europe で利用可能
  • PowerShell コマンドと portal.azure.com 側で作成可能(※注 manage.windowsazure.com 側ポータルでは作成できない
  • 作成するディスクサイズによって IOPS 上限が異なる(※注 5000 IOPS がほしければ 512GB より大きなディスクを作成する必要がある
  • Premium Storage を利用できるインスタンスサイズは STANDARD_DS シリーズのみ(※注 manage.windowsazure.com 側ポータルでは作成できない
  • STANDARD_DS シリーズのサイズにより IOPS 上限が異なる(※注 STANDARD_DS1 だと 3200 IOPS 上限になってしまう

DS シリーズのインスタンスサイズによる IOPS 制限は以下になる。お金をケチって STANDARD_DS1 にすると、Premium Storage の旨味をそこまで引き出せなくなることが分かる。

VM Size CPU cores Max. IOPS Max. Disk Bandwidth
STANDARD_DS1 1 3,200 32 MB per second
STANDARD_DS2 2 6,400 64 MB per second
STANDARD_DS3 4 12,800 128 MB per second
STANDARD_DS4 8 25,600 256 MB per second
STANDARD_DS11 2 6,400 64 MB per second
STANDARD_DS12 4 12,800 128 MB per second
STANDARD_DS13 8 25,600 256 MB per second
STANDARD_DS14 16 50,000 512 MB per second

更に、Premium Storage を利用するディスクサイズによっては 500 IOPS 程度に抑えられる場合がある点も注意。公式ドキュメントのサンプルが 128GB なので、うっかりすると 500 IOPS 程度になる。。。。

Premium Storage Disk Type P10 P20 P30
Disk size 128 GB 512 GB 1024 GB (1 TB)
IOPS per disk 500 2300 5000
Throughput per disk 100 MB per second * 150 MB per second * 200 MB per second *

インスタンスサイズ、ディスクサイズによる制限に注意すれば Premium Storage を活用できる(はず)。次から実際に Premium Storage を利用してみる。

まずは簡単に Premium Storage を使ってみる - STANDARD_DS2 & P10

Premium Storage を利用するためには専用のストレージアカウントを作成する必要がある。以下の様に Type に Premium_LRS と指定する。

# Create Premium Storage
New-AzureStorageAccount -StorageAccountName "<accout name>" -Location "West US" -Type "Premium_LRS"

更に現在 Premium Storage を利用できるインスタンスは STANDARD_DS シリーズのみとなる(つまり、現在は G シリーズのインスタンスと併用できない)。以下の様に InstanceSize に DS シリーズであることを指定して仮想マシンを作成する(まずは STANDARD_DS2 で作成した)。

# Create Instance using Premium Storage 
$image = Get-AzureVMImage | Where-Object {$_.label -like “Windows Server 2012 R2*”} | Sort-Object -Descending PublishedDate | Select-Object -Index 0
$storageAccount = "daisamipremiumaccount"
$adminName = "<username>"
$adminPassword = "<password>"
$vmName ="<vmname>"
$location = "West US"
$vmSize ="Standard_DS2"
$OSDiskPath = "https://" + $storageAccount + ".blob.core.windows.net/vhds/" + $vmName + "_OS_PIO.vhd"
$vm = New-AzureVMConfig -Name $vmName -ImageName $image.ImageName -InstanceSize $vmSize -MediaLocation $OSDiskPath
Add-AzureProvisioningConfig -Windows -VM $vm -AdminUsername $adminName -Password $adminPassword
New-AzureVM -ServiceName $vmName -VMs $VM -Location $location

更に、ディスクをアタッチしてみる。まずは以下の様に 128GB のディスクとしてアタッチしてみた。

# Attach Premium Storage to VM Instance
$vm = Get-AzureVM -ServiceName $vmName -Name $vmName
$LunNo = 1
$path = "http://" + $storageAccount + ".blob.core.windows.net/vhds/" + "myDataDisk_" + $LunNo + "_PIO.vhd"
$label = "Disk " + $LunNo
Add-AzureDataDisk -CreateNew -MediaLocation $path -DiskSizeInGB 128 -DiskLabel $label -LUN $LunNo -HostCaching ReadOnly -VM $vm | Update-AzureVm

こちらに対する CrystalDiskMark の実行結果は以下になった。ご覧のとおり、ディスクサイズが小さいと 500 IOPS 制限に引っかかっている。

-----------------------------------------------------------------------
CrystalDiskMark 3.0.3 x64 (C) 2007-2013 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 byte/s [SATA/300 = 300,000,000 byte/s]

           Sequential Read :    66.587 MB/s
          Sequential Write :    39.150 MB/s
         Random Read 512KB :    67.051 MB/s
        Random Write 512KB :    34.970 MB/s
    Random Read 4KB (QD=1) :     2.097 MB/s [   511.9 IOPS]
   Random Write 4KB (QD=1) :     1.664 MB/s [   406.2 IOPS]
   Random Read 4KB (QD=32) :     2.089 MB/s [   510.1 IOPS]
  Random Write 4KB (QD=32) :     2.089 MB/s [   510.1 IOPS]

  Test : 100 MB [F: 0.1% (0.1/128.0 GB)] (x5)
  Date : 2015/02/14 5:14:31
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)
    afasdfadfadsfa

STANDARD_DS2 & P30 で Premium Storage を使ってみる

ディスクサイズ P10 の制限に引っかかったことが分かったので、次は 1023 GB のディスクを作成してみた。

# Attach Premium Storage to VM Instance
$vm = Get-AzureVM -ServiceName $vmName -Name $vmName
$LunNo = 2
$path = "http://" + $storageAccount + ".blob.core.windows.net/vhds/" + "myDataDisk_" + $LunNo + "_PIO.vhd"
$label = "Disk " + $LunNo
Add-AzureDataDisk -CreateNew -MediaLocation $path -DiskSizeInGB 1023 -DiskLabel $label -LUN $LunNo -HostCaching ReadOnly -VM $vm | Update-AzureVm

結果は以下の通り、5000 IOPS 程度出ている。

-----------------------------------------------------------------------
CrystalDiskMark 3.0.3 x64 (C) 2007-2013 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 byte/s [SATA/300 = 300,000,000 byte/s]

           Sequential Read :    66.587 MB/s
          Sequential Write :    40.273 MB/s
         Random Read 512KB :    67.040 MB/s
        Random Write 512KB :    35.620 MB/s
    Random Read 4KB (QD=1) :    20.947 MB/s [  5114.0 IOPS]
   Random Write 4KB (QD=1) :     1.670 MB/s [   407.7 IOPS]
   Random Read 4KB (QD=32) :    20.896 MB/s [  5101.6 IOPS]
  Random Write 4KB (QD=32) :    20.943 MB/s [  5113.1 IOPS]

  Test : 100 MB [G: 0.0% (0.2/1023.0 GB)] (x5)
  Date : 2015/02/14 5:57:24
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)

念のため 600GB のディスクサイズだとどうなるか確かめた。

# Attach Premium Storage to VM Instance
$vm = Get-AzureVM -ServiceName $vmName -Name $vmName
$LunNo = 3
$path = "http://" + $storageAccount + ".blob.core.windows.net/vhds/" + "myDataDisk_" + $LunNo + "_PIO.vhd"
$label = "Disk " + $LunNo
Add-AzureDataDisk -CreateNew -MediaLocation $path -DiskSizeInGB 600 -DiskLabel $label -LUN $LunNo -HostCaching ReadOnly -VM $vm | Update-AzureVM

こちらでも P30 の 5000 IOPS が出ている。

-----------------------------------------------------------------------
CrystalDiskMark 3.0.3 x64 (C) 2007-2013 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 byte/s [SATA/300 = 300,000,000 byte/s]

           Sequential Read :    66.576 MB/s
          Sequential Write :    40.191 MB/s
         Random Read 512KB :    67.040 MB/s
        Random Write 512KB :    35.677 MB/s
    Random Read 4KB (QD=1) :    20.940 MB/s [  5112.3 IOPS]
   Random Write 4KB (QD=1) :     1.616 MB/s [   394.4 IOPS]
   Random Read 4KB (QD=32) :    20.893 MB/s [  5100.9 IOPS]
  Random Write 4KB (QD=32) :    20.892 MB/s [  5100.5 IOPS]

  Test : 100 MB [H: 0.0% (0.2/600.0 GB)] (x5)
  Date : 2015/02/14 6:57:53
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)
  

Storage Pool の利用

更に、Storage Pool を利用して Premium Storage のディスクを束ねて利用してみた。まずは STANDARD_DS2 のまま P30x2 での速度を確認した。8000 IOPS 以上出ているが、こちらは STANDARD_DS2 のインスタンスサイズによる IOPS 制限を受けている。

-----------------------------------------------------------------------
CrystalDiskMark 3.0.3 x64 (C) 2007-2013 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 byte/s [SATA/300 = 300,000,000 byte/s]

           Sequential Read :    67.109 MB/s
          Sequential Write :    66.905 MB/s
         Random Read 512KB :    67.040 MB/s
        Random Write 512KB :    57.867 MB/s
    Random Read 4KB (QD=1) :    33.477 MB/s [  8173.0 IOPS]
   Random Write 4KB (QD=1) :     1.588 MB/s [   387.6 IOPS]
   Random Read 4KB (QD=32) :    33.525 MB/s [  8184.7 IOPS]
  Random Write 4KB (QD=32) :    33.420 MB/s [  8159.2 IOPS]

  Test : 100 MB [F: 0.0% (0.2/1197.9 GB)] (x5)
  Date : 2015/02/14 8:03:39
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)

以下のコマンドを利用して Standard_DS14 サイズに変更した。

# Standard_DS14 に変更
Get-AzureVM -ServiceName <service name> -Name <instance name> | Set-AzureVMSize -InstanceSize Standard_DS14 | Update-AzureVM

再度 IOPS を計測すると、今度は 10000 IOPS 以上出ており 5000 IOPSx2 を束ねた速度が出ていることが分かる。

-----------------------------------------------------------------------
CrystalDiskMark 3.0.3 x64 (C) 2007-2013 hiyohiyo
                           Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 byte/s [SATA/300 = 300,000,000 byte/s]

           Sequential Read :   408.735 MB/s
          Sequential Write :   106.377 MB/s
         Random Read 512KB :   408.468 MB/s
        Random Write 512KB :    56.950 MB/s
    Random Read 4KB (QD=1) :    40.708 MB/s [  9938.4 IOPS]
   Random Write 4KB (QD=1) :     1.469 MB/s [   358.6 IOPS]
   Random Read 4KB (QD=32) :    41.542 MB/s [ 10142.2 IOPS]
  Random Write 4KB (QD=32) :    41.382 MB/s [ 10103.0 IOPS]

  Test : 100 MB [F: 0.0% (0.2/1197.9 GB)] (x5)
  Date : 2015/02/15 1:45:38
    OS : Windows Server 2012 R2 Datacenter (Full installation) [6.3 Build 9600] (x64)

Storage Pool で束ねるディスクをさらに増やすことで IOPS は増すことができそうなので、他の方にもチャレンジしてほしい。

Microsoft Azure SDK for Java の Management Library を利用する

以前に Windows Azure SDK for .NET の Management Library を利用して Webサイト を動的に作成してみる を記載したが、今回は JavaSDK で Management API を操作する。

証明書の準備

まず、 C:\Program Files (x86)\Windows Kits\8.1\bin\x86 以下に存在する makecert コマンドを利用して cer ファイルを作成する。以下のコマンドを利用したので、ファイル名等は適宜変更してほしい。

>makecert -r -pe -a sha1 -n "CN=For Java SDK Certification" -ss my -len 2048 -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 ManagementJavaSDK.cer

次に、作成した *.cer ファイルをダブルクリックし、証明書のエクスポートを実施して *.pfx ファイル(今回は ManagementJavaSDK.pfx )を作成する。
f:id:waritohutsu:20150208023553p:plain

更に、以下のコマンドにて Java で利用する keystore の *.jks ファイル(今回は ManagementJavaSDK.jks )を作成する。

>keytool -importkeystore -srckeystore c:\Temp\ManagementJavaSDK.pfx -dest keystore ManagementJavaSDK.jks -srcstoretype pkcs12 -deststoretype JKS

最後に、作成した *.cer ファイルを管理ポータルに以下の様にアップロードしておく(設定 - 管理証明書 以下に配置する点に注意)。
f:id:waritohutsu:20150208023602p:plain

Java アプリケーションの作成

こちらはシンプルに Maven プロジェクトを作成すれば対応可能だ。それぞれコードを記載する。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mycompany</groupId>
	<artifactId>HelloAzureSDK</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>jar</packaging>
	<dependencies>
		<dependency>
			<groupId>com.microsoft.azure</groupId>
			<artifactId>azure-management-network</artifactId>
			<version>0.7.0</version>
		</dependency>
	</dependencies>
</project>
package com.mycompany;

import java.io.IOException;
import java.net.InetAddress;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import com.microsoft.windowsazure.Configuration;
import com.microsoft.windowsazure.core.utils.KeyStoreType;
import com.microsoft.windowsazure.exception.ServiceException;
import com.microsoft.windowsazure.management.configuration.ManagementConfiguration;
import com.microsoft.windowsazure.management.network.NetworkManagementClient;
import com.microsoft.windowsazure.management.network.NetworkManagementService;
import com.microsoft.windowsazure.management.network.StaticIPOperations;

public class Main {

	public static void main(String args[]) throws IOException,
			URISyntaxException, ServiceException, ParserConfigurationException,
			SAXException {

		// キーストア等々もろもろ
		String subscriptionId = "120a0546-b790-4979-84da-09d671c0c376";
		String keyStorePath = "C:\\Temp\\ManagementJavaSDK.jks";
		String keyStorePassword = "P@ssw0rd00";

		Configuration config = ManagementConfiguration.configure(null,
				subscriptionId, //
				keyStorePath, //
				keyStorePassword, //
				KeyStoreType.fromString("jks"));
		NetworkManagementClient networkManagementClient = NetworkManagementService
				.create(config);

		// 仮想ネットワーク内の静的IP利用チェック
		StaticIPOperations so = networkManagementClient
				.getStaticIPsOperations();

		List<String> ipList = new ArrayList<String>();
		ipList.add("10.0.0.21"); // 利用可能な IP
		ipList.add("10.20.0.21"); // サブネット範囲外の IP

		String vnetName = "vnet-alwayson";

		for (String ip : ipList) {
			try {
				boolean isAvailable = so.check(vnetName,
						InetAddress.getByName(ip)).isAvailable();
				System.out.println(ip + " is " + isAvailable + " on "
						+ vnetName);
			} catch (ServiceException ex) {
				System.out.println(ip + " is false on " + vnetName);
				ex.printStackTrace();
			}
		}
	}
}

上記の実行結果は以下な感じ。

log4j:WARN No appenders could be found for logger (org.apache.http.client.protocol.RequestAddCookies).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
10.0.0.1 is false on vnet-alwayson
10.20.0.21 is false on vnet-alwayson
com.microsoft.windowsazure.exception.ServiceException: BadRequest: The address 10.20.0.21 is not contained in any of the subnets in the virtual network.
	at com.microsoft.windowsazure.exception.ServiceException.createFromXml(ServiceException.java:216)
	at com.microsoft.windowsazure.management.network.StaticIPOperationsImpl.check(StaticIPOperationsImpl.java:165)
	at com.mycompany.Main.main(Main.java:52)

Azure Websites 上の Java アプリをリモートデバッグする

最近の投稿は Java 成分が多めになっているが、昨今の職種と役割のせいだと信じたいところ。さて、今回は Azure Websites 上の Java アプリにリモートデバッグを行う。当然ながらローカル環境と Azure Websites 上では少なからず差異があるため、今回紹介するリモートデバッグの機能は有用な人が多いはずだ。

こちらは既に Microsoft からソースコードを含めた利用方法が GitHub/Azure/azure-websites-java-remote-debugging に公開されている。今回はこちらを利用して実際に Azure Websites 上の Java アプリをリモートデバッグする。上記のソースコードを一読すると理解できると思うが、リモートデバッグ自体は既存の JDWP‐Java Debug Wire Protocol を利用しているので、こちらを理解している人であればとっかかりはあまり難しくないだろう。

リモートデバッグを試す

以下がリモートデバッグを試すまでの全体の流れになる。初回の疎通を通すまでは以下を参考にした方が楽にできるだろう。

  1. Websites を作成して「構成」タブから WebSocket を有効化する(おすすめはギャラリーからの Tomcat 7.x 作成
  2. Web.config に追記を行う
  3. 自作アプリの配置
  4. https://github.com/Azure/azure-websites-java-remote-debugging をダウンロードして DebugSession.bat の実行
  5. ブラウザから Azure Websites の自作アプリにアクセス

まず、新規に Websites を作成するが、こちらは 無料 モードでも 標準 モードでも問題ない。次に編集する Web.config があらかじめ配置されるギャラリーから「Apache Tomcat 7」がお勧めだ。
f:id:waritohutsu:20150125075205p:plain:w400
Websites 作成後、以下を参考に構成タブから WebSocket を有効化する。
f:id:waritohutsu:20150125075249p:plain

次に、kudu( https://<サイト名>.scm.azurewebsites.net/)にアクセスして D:\home\site\wwwroot\web.config を以下の様に編集する。デバッグオプションが追加していることが確認できるだろう。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="httpPlatformHandler" path="*" verb="*" 
                 modules="httpPlatformHandler" resourceType="Unspecified" />
        </handlers>
        <httpPlatform processPath="d:\home\site\wwwroot\bin\apache-tomcat-7.0.52\bin\startup.bat">
            <environmentVariables>
                <environmentVariable name="CATALINA_OPTS" value="-Dport.http=%HTTP_PLATFORM_PORT%" />
                <environmentVariable name="CATALINA_HOME" value="d:\home\site\wwwroot\bin\apache-tomcat-7.0.52" />                
                <environmentVariable name="JAVA_OPTS" value="-Djava.net.preferIPv4Stack=true -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=127.0.0.1:%HTTP_PLATFORM_DEBUG_PORT%" />
            </environmentVariables>
        </httpPlatform>
    </system.webServer>
</configuration>

更に、自作アプリを Websites 上に配置する。Eclipse から新規プロジェクト作成を選択し、Dynamic Web Project を選択して以下の様に index.jsp を配置する。
f:id:waritohutsu:20150125075109p:plain

上記でも紹介した Kudu の Debug console を利用して D:\home\site\wwwroot\bin\apache-tomcat-7.0.52\webapps\ROOT 以下のバックアップを取得したうえで作成した Java アプリを配置する。

次にリモートデバッグ用のツールを実行する。azure-websites-java-remote-debugging から取得したファイルの bin\DebugSession.bat を以下の実行例に沿って実行する。

>DebugSession.bat -p 8000 -s <sitename>.scm.azurewebsites.net -u <username> -w <password> -t
1 25, 2015 7:57:37 午前 org.azure.waws.DebugSession startSession
情報: Waiting for debugger to connect on 8000 ...

ここでの注意として、username には sitename\username を指定してはいけない点だ(例:normalian)。

Eclipse から [Debug As]-[Debug Configurations..] を選択し、以下の実行例に沿ってアプリケーションをデバッグ実行する。
f:id:waritohutsu:20150125075929p:plain

最後にブラウザからサイトにアクセスすると、以下の様に Eclipse 上からリモートデバッグが可能となる。
f:id:waritohutsu:20150125080600p:plain

最後に注意点として、Azure Websites を無料モードで利用している場合にCPU使用制限に引っかかってインスタンスが再起動される場合があるので、長時間放置する場合には WebSocket のコネクションが切れている場合があるので注意が必要だ。