Hatena::ブログ(Diary)

ablog このページをアンテナに追加 RSSフィード Twitter

2017-01-09

EM監視メトリックのWeblogicのアクティブ・セッションは何か

おそらく、TCP接続確立済のHTTPセッション数ではないかと思う。とりあえずメモ。

違いました。 id:yamadamn さんにコメントいただきました。

今更感のあるツッコミですが多分違います。

セッションという言葉は色々と使われますが、Servlet仕様のHttpSessionオブジェクトの数でしょうね。

https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html

WLSとしてはOpenSessionsCurrentCountとして取得できるものを指しているはずです。

https://docs.oracle.com/cd/E26854_01/em.121/b70510/wls.htm

https://docs.oracle.com/middleware/12212/wls/WLACH/pagehelp/J2EEappdeploymentsmonitorwebapptabletitle.html

EM監視メトリックのWeblogicのアクティブ・セッションは何か - ablog

教えていただいたServlet仕様のHttpSessionについて一部引用。

The servlet container uses this interface to create a session between an HTTP client and an HTTP server. The session persists for a specified time period, across more than one connection or page request from the user. A session usually corresponds to one user, who may visit a site many times. The server can maintain a session in many ways such as using cookies or rewriting URLs.

HttpSession (Java(TM) EE 7 Specification APIs)

サーブレットにアクセスしてHttpSessionオブジェクトが生成されるとWeblogicなどのJavaアプリケーションサーバでHttpSessionオブジェクトは一定期間生存する。従って、「HttpSessionオブジェクトの数 >= TCPセッション数」となると思われる。

http(s)はステートレスなプロトコル、keep-alive を使うと接続を維持するが*1、通常 keep-alive(十数秒〜1分とか)よりもセッションタイムアウト(20分とか)のほうが長いことが多い。

例えば、ブラウザでアクセスしてHttpSessionオブジェクトが生成された後、ブラウザを「×」で落として、起動してアクセスすると前のHttpSessionオブジェクトが残って、これを繰り返すとセッション数はどんどん増えると思われる。

ちなみに元々のTCPセッション的な意味で取得するのでしたら、OpenSocketsCurrentCountですね。

https://docs.oracle.com/middleware/12212/wls/WLACH/pagehelp/Corecoreserverservertitle.html

さっき貼ったEMのマニュアルURLだと"アクティブ・ソケット"って書いてあるほうですね。

EM監視メトリックのWeblogicのアクティブ・セッションは何か - ablog

こちらも教えていただいたマニュアルから一部引用。

Currently Open Sockets: The current number of sockets registered for socket muxing on this server.

Servers

以下は一応残しておく。

Systems Performance: Enterprise and the Cloud

Systems Performance: Enterprise and the Cloud

  • 10.4. Architecture
    • 10.4.1. Protocols

Three-Way Handshake

Connections are established using a three-way handshake between the hosts. One host passively listens for connections; the other actively initiates the connection. To clarify terminology: passive and active are from [RFC 793]; however, they are commonly called listen and connect respectively, after the socket API. For the client/server model, the server performs listen and the client performs connect.

The three-way handshake is pictured in Figure 10.6.

f:id:yohei-a:20170109084203p:image:w360

The TCP protocol was described earlier. This section describes performance features of the kernel TCP implementation: backlog queues and buffers.

Bursts of connections are handled by using backlog queues. There are two such queues, one for incomplete connections while the TCP handshake completes (also known as the SYN backlog), and one for established sessions waiting to be accepted by the application (also known as the listen backlog). These are pictured in Figure 10.10.

Only one queue was used in earlier kernels, and it was vulnerable to SYN floods. A SYN flood is a type of DoS attack that involves sending numerous SYNs to the listening TCP port from bogus IP addresses. This fills the backlog queue while TCP waits to complete the handshake, preventing real clients from connecting.

With two queues, the first can act as a staging area for potentially bogus connections, which are promoted to the second queue only once the connection is established. The first queue can be made long to absorb SYN floods and optimized to store only the minimum amount of metadata necessary.

The length of these queues can be tuned independently (see Section 10.8, Tuning). The second can also be set by the application as the backlog argument to listen().

f:id:yohei-a:20170109084748p:image:w360


参考

*1タイムアウトするまで

2017-01-03

Java Flight Recorder と Java Mission Control とは

  • Java Flight Recorder(JFR) は Oracle JDK に同梱されている稼働統計収集機能
  • Java Mission Control(JMC) は HotSpot JVM*1 に同梱されている JFR で収集したデータをGUI解析するツール*2
  • Java Flight RecorderとJava Mission Controlは低レベルおよび事後インシデン ト分析を可能にする詳細なランタイム情報を継続的に集めるための完全なツー ル・チェーンを作成します。
  • Java Flight Recorderは、Oracle JDKに組み込まれているプロファイリングとイベント収集フレームワークです。Java管理者およ び開発者は、Java Virtual Machine (JVM) とJavaアプリケーションがどのよう に動作しているかについての詳細な低レベル情報を収集することができます。
  • Java Mission Controlは、Java Flight Recorderによって収集されたデータを効 率的かつ広範囲に詳細な分析を可能にする高度なツール・セットです。ツール・ チェーンは、開発者や管理者が、ローカルで実行している、あるいは本番環境で デプロイされているJavaアプリケーションからデータを収集し分析することを可 能にします。
  • Oracle JDK 7 Update 40 (7u40) のリリースでスタートしたJava Mission Controlは、HotSpot JVMバンドルされています。
Java Mission Control

参考

Windows で Java Mission Control(JMC) のヒープサイズを変更する

背景

  • WindowsWeblogicJava Flight Recorder(JFR) のダンプファイルを分析していたら、動作が重い(特にイベントタブのスレッドごとのグラフ)ので、ヒープサイズを大きくしてみた。

変更方法

JDKインストールディレクトリ\bin\jmc.ini の -vmargs のセクションに -XX:InitialHeapSize(=-Xms)、-XX:MaxHeapSize(=-Xmx) を追記する。

-startup
../lib/missioncontrol/plugins/org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar
--launcher.library
../lib/missioncontrol/plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20141007-2033
--launcher.appendVmargs
-vm
../jre/bin/
-vmargs
-XX:+UseG1GC
-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder
-XX:FlightRecorderOptions=defaultrecording=true
-XX:InitialHeapSize=1g # ★ココ
-XX:MaxHeapSize=6g # ★ココ
-Djava.net.preferIPv4Stack=true

確認

> cd C:\Program Files\Java\jdk1.8.0_92\bin
> jcmd -l
3732
7588 sun.tools.jcmd.JCmd -l

> jcmd 3732 VM.flags
3732:
-XX:CICompilerCount=3 -XX:ConcGCThreads=1 -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true -XX:G1HeapRegionSize=1048576 -XX:InitialHeapSize=1073741824★ -XX:MarkStackSize=4194304 -XX:MaxHeapSize=6442450944★ -XX:MaxNewSize=3865051136 -XX:MinHeapDeltaBytes=1048576 -XX:+UnlockCommercialFeatures -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:-UseLargePagesIndividualAllocation

InitialHeapSize=1073741824、MaxHeapSize=6442450944 と変更が反映されている。


参考

Oracle JDK の JFR のダンプファイルを小さく分割する方法

Oracle JDKJava Flight Recorder(JFR) のダンプファイルを Java Mission Control(JMC) で開いて分析してると重いので、小さく分割する方法を調べてたら、id:yamadamn さんに教えていただいたのでメモ。分割したら画面の応答が速くなり、快適に分析できるようになりました。


インストール


書式

java -jar split.jar JFRのダンプファイル名 分割サイズ(デフォルト50MB)

実行例

> java -jar .\split.jar 2016_12_31_23_59_59.jfr 5
Examining recording 2016_12_31_23_59_59.jfr ...
Found 8 chunks.
Average chunk size: 10.9 MiB
Target size: 5 MiB
Chunk aligned target size: 10.9 MiB
The recording will be split into 8 files with at most 1 chunks per file.
Writing ... \2016_12_31_23_59_590.jfr ... finished!
Writing ... \2016_12_31_23_59_591.jfr ... finished!
Writing ... \2016_12_31_23_59_592.jfr ... finished!
Writing ... \2016_12_31_23_59_593.jfr ... finished!
Writing ... \2016_12_31_23_59_594.jfr ... finished!
Writing ... \2016_12_31_23_59_595.jfr ... finished!
Writing ... \2016_12_31_23_59_596.jfr ... finished!
Writing ... \2016_12_31_23_59_597.jfr ... finished!

実行結果

> dir

2017/01/03  08:05    <DIR>          .
2017/01/03  08:05    <DIR>          ..
2016/12/21  13:01        91,288,687 2016_12_31_23_59_59.jfr ★元ファイル(87MB)
2017/01/03  08:05        14,693,074 2016_12_31_23_59_590.jfr ★↓分割されたファイル(14MB)
2017/01/03  08:05        14,320,595 2016_12_31_23_59_591.jfr
2017/01/03  08:05        14,320,706 2016_12_31_23_59_592.jfr
2017/01/03  08:05        14,452,690 2016_12_31_23_59_593.jfr
2017/01/03  08:05        14,608,565 2016_12_31_23_59_594.jfr
2017/01/03  08:05        14,769,525 2016_12_31_23_59_595.jfr
2017/01/03  08:05         3,789,594 2016_12_31_23_59_596.jfr
2017/01/03  08:05           333,938 2016_12_31_23_59_597.jfr
2017/01/03  07:08             9,311 split.jar ★分割プログラム

参考

*1Oracle JDK 7 Update 40 (7u40)以降

*2:実行中のJavaの状況のリアルタイムモニタリングも可能

*3:JFR のダンプファイルと同じ場所でなくても、任意のフォルダに保存して実行時にパスを指定すればよい

2017-01-01

Python ではてなフォトライフの RSS をスクレイピングして最後に画像がアップされた時刻を取得する

はてなフォトライフRSSスクレイピングして最後に画像がアップされた時刻を取得する Python スクリプト

<item rdf:about="http://f.hatena.ne.jp/yohei-a/20161211091424">

...

<dc:date>2016-12-11T09:14:24+09:00</dc:date> ★これの最大値を取得する
</item>
<item rdf:about="http://f.hatena.ne.jp/yohei-a/20161211091423">

...

<dc:date>2016-12-11T09:14:23+09:00</dc:date>

...

</item>
<item rdf:about="http://f.hatena.ne.jp/yohei-a/20161209080817">

...

<dc:date>2016-12-09T08:08:17+09:00</dc:date>

...

</item>
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import urllib2
from bs4 import BeautifulSoup
from datetime import datetime

html = urllib2.urlopen('http://f.hatena.ne.jp/yohei-a/rss')
soup = BeautifulSoup(html, "html.parser")
ts_list = []

for item in soup.find_all("dc:date"):
	ts_str = item.contents[0]
	ts_date = datetime.strptime(ts_str[0:18], '%Y-%m-%dT%H:%M:%S')
	ts_list.append(ts_date)

print max(ts_list)
  • 実行結果
$ python max_dc_date.py 
2016-12-11 09:14:02

参考

2016-12-31

Python ではてなフォトライフの RSS をスクレイピングして画像をダウンロードする

はてなフォトライフRSSスクレイピングして、画像の URI を取得してダウンロードするする Python スクリプト


...

<item rdf:about="http://f.hatena.ne.jp/yohei-a/20161211091424">

...

<dc:date>2016-12-11T09:14:24+09:00</dc:date>
<hatena:imageurl>
http://cdn-ak.f.st-hatena.com/images/fotolife/y/yohei-a/20161211/20161211091424.png ★この URI を取出す
</hatena:imageurl>
<hatena:imageurlsmall>
http://cdn-ak.f.st-hatena.com/images/fotolife/y/yohei-a/20161211/20161211091424_m.jpg
</hatena:imageurlsmall>
<hatena:imageurlmedium>
http://cdn-ak.f.st-hatena.com/images/fotolife/y/yohei-a/20161211/20161211091424_120.jpg
</hatena:imageurlmedium>
<hatena:syntax>f:id:yohei-a:20161211091424p:image</hatena:syntax>
<hatena:colors>
<hatena:color>white</hatena:color>
<hatena:color>blue</hatena:color>
</hatena:colors>
</item>
<item rdf:about="http://f.hatena.ne.jp/yohei-a/20161211091423">

...
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import urllib2
from bs4 import BeautifulSoup

html = urllib2.urlopen('http://f.hatena.ne.jp/yohei-a/rss')
soup = BeautifulSoup(html, "html.parser")

for item in soup.find_all("hatena:imageurl"): # <hatena:imageurl> を取出して一件ずつループ
	img_uri = item.contents[0] # item から <hatena:imageurl> タグの中身の URI を取出す
	img_filename = os.path.basename(img_uri)
	r = urllib2.urlopen(img_uri)
	f = open(img_filename, "wb")
	f.write(r.read())
	r.close()
	f.close()
  • 実行する
$ python dl_fotolife.py
  • 実行結果
$ ls -lt|head
total 7264
-rw-r--r--+ 1 yazekats None 226274 Dec 31 13:12 20160515181139.png
-rw-r--r--+ 1 yazekats None  26866 Dec 31 13:12 20160529032112.jpg
-rw-r--r--+ 1 yazekats None  18160 Dec 31 13:12 20160529033413.jpg
-rw-r--r--+ 1 yazekats None  21304 Dec 31 13:12 20160529033826.jpg
-rw-r--r--+ 1 yazekats None  22360 Dec 31 13:12 20160530093602.jpg
-rw-r--r--+ 1 yazekats None  19574 Dec 31 13:12 20160530093603.jpg
-rw-r--r--+ 1 yazekats None  53302 Dec 31 13:12 20160530094316.jpg
-rw-r--r--+ 1 yazekats None  65751 Dec 31 13:12 20160530184902.jpg
-rw-r--r--+ 1 yazekats None  28564 Dec 31 13:12 20160530184903.jpg

参考

Instead of getting them as a list, you can iterate over a tag’s children using the .children generator:

for child in title_tag.children:
    print(child)
# The Dormouse's story
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation

2016-12-25

SQLテスト・ケース・ビルダーで再現ケースを作成する

実行計画絡みの性能トラブルシューティングでよく使うので書いておきます。


エクスポート

  • 共有プールに共有カーソルがキャッシュされているか確認する
SELECT COUNT(1) FROM V$SQL WHERE SQL_ID='a5ks9fhw2v9s1' AND PLAN_HASH_VALUE=272002086;
DECLARE
	V_TESTCASE CLOB;
BEGIN
	DBMS_SQLDIAG.EXPORT_SQL_TESTCASE(
	DIRECTORY  => 'TEMP_DIR', /* ディレクトリオブジェクトを指定 */
	sql_id => 'a5ks9fhw2v9s1',
	plan_hash_value => 1001824601,
	exportData => FALSE,
	exportPkgbody=>TRUE,
	testcase_name => 'tc_a5ks9fhw2v9s1_272002086_',
	testcase   => V_TESTCASE);
END;
/
select DIRECTORY_PATH from dba_directories where DIRECTORY_NAME = 'TEMP_DIR';
!
cd /path/to/dir # ↑で確認した DIRECTORY_PATH に移動する
tar cfvz tc_tc_a5ks9fhw2v9s1_272002086.tar.gz tc_tc_a5ks9fhw2v9s1_272002086_*
  • tc_tc_a5ks9fhw2v9s1_272002086.tar.gz を回収する。

インポート

BEGIN
    DBMS_SQLDIAG.IMPORT_SQL_TESTCASE(
    directory => 'TEMP_DIR'         --再現ケース配置先ディレクトリ
   ,importdata => false            --データをIMPORTするか
   ,importpkgbody => true             --依存パッケージをIMPORTするか
   ,filename => 'tc_a5ks9fhw2v9s1_272002086_main.xml'
     );
END;
/


参考

統計情報とSQL計画ディレクティブを操作するコマンド集

統計情報

  • ユーザー統計表を作成する
exec dbms_stats.create_stat_table(ownname=>'SCOTT', stattab=>'STAT_TAB_20160223');
exec dbms_stats.export_table_stats(ownname=>'SCOTT', tabname=>'EMP', stattab=>'STAT_TAB_20160223', cascade=>true);
update STAT_TAB set c1 = 'EMP', c5='SCOTT';
commit;
exec dbms_stats.import_table_stats(ownname=>'SCOTT', tabname=>'EMP', stattab=>'STAT_TAB_MOD', cascade=>true, no_invalidate=>false);
exec dbms_stats.delete_table_stats(ownname=>'SCOTT', tabname=>'EMP'e, no_invalidate=>false);
exec dbms_stats.drop_extended_stats(ownname=>'SCOTT', tabname=>'EMP', extension=>'(PER_NAME_ENT_YEAR,ACTIVE_FLG)');
exec dbms_stats.delete_column_stats(ownname=>'SCOTT', tabname=>'EMP', colname=>'X_PARTITION_CONC_KEY', col_stat_type=>'HISTOGRAM'e, no_invalidate=>false);
  • 統計情報をリストアする。
exec dbms_stats.restore_table_stats(ownname=>'SCOTT', tabname=>'EMP', as_of_timestamp=>'2016-03-02 12:00:00.000000000', no_invalidate=>false);
select dbms_stats.get_prefs(pname=>'publish', ownname=>'SCOTT', tabname=>'EMP') from dual;

実行計画

col hash_value for 99999999999999
col address  for a100
select hash_value, address from v$sqlarea where sql_id = 'cwxqhpbqj4vzy';
exec sys.dbms_shared_pool.purge('0000003A9155F7F8, 3977408510','C');
alter session set statistics_level=all;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

SQL計画ディレクティブ

DECLARE
	CURSOR CU IS SELECT DISTINCT A.DIRECTIVE_ID DIRECTIVE_ID
		FROM DBA_SQL_PLAN_DIRECTIVES A, DBA_SQL_PLAN_DIR_OBJECTS B
	WHERE B.OWNER = 'SCOTT'
		AND A.DIRECTIVE_ID = B.DIRECTIVE_ID;
BEGIN
	FOR REC IN CU LOOP
		BEGIN
			DBMS_SPD.DROP_SQL_PLAN_DIRECTIVE(REC.DIRECTIVE_ID);
		EXCEPTION WHEN OTHERS THEN
			DBMS_OUTPUT.PUT_LINE('Failed to drop DIRECTIVE_ID:'||REC.DIRECTIVE_ID||', '||SQLCODE||':'||SQLERRM);
		END;
	END LOOP;
END;
/
DECLARE
	CURSOR CU IS SELECT DISTINCT A.DIRECTIVE_ID DIRECTIVE_ID
		FROM DBA_SQL_PLAN_DIRECTIVES A, DBA_SQL_PLAN_DIR_OBJECTS B
	WHERE OWNER = 'SCOTT'
BEGIN
	FOR REC IN CU LOOP
		BEGIN
			DBMS_SPD.ALTER_SQL_PLAN_DIRECTIVE(REC.DIRECTIVE_ID,'ENABLED','NO');
		EXCEPTION WHEN OTHERS THEN
			DBMS_OUTPUT.PUT_LINE('Failed to disable DIRECTIVE_ID:'||REC.DIRECTIVE_ID||', '||SQLCODE||':'||SQLERRM);
		END;
	END LOOP;
END;
/
DECLARE
	CURSOR CU IS SELECT DISTINCT A.DIRECTIVE_ID DIRECTIVE_ID
		FROM DBA_SQL_PLAN_DIRECTIVES A, DBA_SQL_PLAN_DIR_OBJECTS B
	WHERE OWNER = 'SCOTT'
BEGIN
	FOR REC IN CU LOOP
		BEGIN
			DBMS_SPD.ALTER_SQL_PLAN_DIRECTIVE(REC.DIRECTIVE_ID,'ENABLED','YES');
		EXCEPTION WHEN OTHERS THEN
			DBMS_OUTPUT.PUT_LINE('Failed to disable DIRECTIVE_ID:'||REC.DIRECTIVE_ID||', '||SQLCODE||':'||SQLERRM);
		END;
	END LOOP;
END;
/
impdp SCOTT/Welcome1 directory=DP_DIR dumpfile=PROD_SQL_DIRECTIVE_20160210.dmp logfile=imp_PROD_SQL_DIRECTIVE_20160224.log;
select dbms_spd.unpack_stgtab_directive(table_name=>'PROD_SQL_DIRECTIVE_20160210',table_owner=>'SCOTT') from dual;
  • SQL計画ディレクティブをバックアップする
begin
  dbms_spd.create_stgtab_directive(
    table_name => 'DEV_SQL_DIRECTIVE_20160224',
    table_owner => 'SCOTT',
    tablespace_name => 'USERS');
end;
/
select dbms_spd.pack_stgtab_directive(table_name=>'DEV_SQL_DIRECTIVE_20160224',table_owner=>'SCOTT') from dual;
select count(1) from DEV_SQL_DIRECTIVE_20160224;
exec dbms_stats.gather_table_stats(ownname=>'SCOTT', tabname=>'DEV_SQL_DIRECTIVE_20160224', cascade=>true, no_invalidate=>false);
!expdp SCOTT/ tables=DEV_SQL_DIRECTIVE_20160224 directory=dp_dir dumpfile=DEV_SQL_DIRECTIVE_20160224.dmp logfile=exp_DEV_SQL_DIRECTIVE_20160224.log

メモ

set echo on
set time on
set timing on
set pagesize 50000
set linesize 32767
alter session set current_schema=SCOTT;
  • OPTIMIZER_FEATURES_ENABLE変更
alter session set OPTIMIZER_FEATURES_ENABLE = '11.2.0.3';

*1:SQL_ID と PLAN_HASH_VALUE が変わらないようアプリケーションから発行されるのとバインド変数名、スペース、改行含め全く同じSQL文で実行する

*2解凍したもの