Hatena::ブログ(Diary)

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

2017-12-06

EMRクラスターを起動するシェルスクリプト

同じ名前のクラスターが存在したらスルーするEMRクラスター作成シェルスクリプト。ただし、同時実行すると複数クラスターが作成される。

厳密にやりたい場合は S3をトリガーとするLambdaの冪等性をDynamoDBで実現してみた | Developers.IO のような方式にする必要がある。


  • create-emr.sh
#!/bin/bash
export LANG=en_US.UTF-8

is_cluster=`aws emr list-clusters|jq -r '.Clusters[]|select(.Name=="test-cluster" and .Status.State != "TERMINATED")'|wc -l`

if [ $is_cluster -gt 0 ] ; then
	echo "test-cluster is already exists"
else
	echo "create test-cluster"
	aws emr create-cluster \
	--name test-cluster \
	--ami-version 3.4.0 \
	--applications Name=Hive Name=Hue \
	--instance-groups InstanceGroupType=MASTER,InstanceCount=1,InstanceType=c3.xlarge \
	InstanceGroupType=CORE,InstanceCount=2,InstanceType=c3.xlarge  \
	--use-default-roles
fi
% bash ./create_emr.sh
create test-cluster
{
    "ClusterId": "j-R9X68AQHT4VS"
}
% bash create_emr.sh
test-cluster is already exists
% bash create_emr.sh & bash create_emr.sh & bash create_emr.sh
[1] 93606
[2] 93607
create test-cluster
create test-cluster
create test-cluster
{
    "ClusterId": "j-2HGB6SSEQBTCR"
}
{
    "ClusterId": "j-1IPYAEKJBIPCE"
}
[2]  + done       bash create_emr.sh
{
    "ClusterId": "j-2QL5MJM1BNC2U"
}
[1]  + done       bash create_emr.sh

参考

2017-11-04

macOS Sierra でスワップを無効化する

macOS Sierraスワップを無効化した手順のメモ。

macOS Sierra では System Integrity Protection (SIP) でシステムファイルが保護されているので、リカバリモードで起動して、SIP を無効化後にスワップ(Pagerデーモン自動起動)を無効化し、SIP を元に戻した。


手順

リカバリモードで起動して SIP を無効化する

f:id:yohei-a:20171105003836j:image:w360

  • 「主に日本語を使用する」を選択する

f:id:yohei-a:20171105003417j:image:w360

f:id:yohei-a:20171105003829j:image:w360

  • SIP を無効化する
-bash-3.2# csrutil disable
Successfully disabled System Integrity Protection. Please restart the machine for the changes to take effetc.

スワップを無効化する
$ sudo launchctl list|grep dynamic_pager
-	0	com.apple.dynamic_pager ★ Pager デーモンの自動起動が有効
$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist
$ sudo launchctl list|grep dynamic_pager
$ ★Pager デーモンの自動起動が無効になっている

リカバリモードで起動して SIP を有効化する (元に戻す)
  • 再起動する
  • 起動時に Command + R を押し続ける(ログイン画面になる前)
  • 「主に日本語を使用する」を選択する
  • 画面上部のメニューの [ユーティティ]-[ターミナル] を選択する
  • SIP を有効化する
-bash-3.2# csrutil enaable
Successfully disabled System Integrity Protection. Please restart the machine for the changes to take effetc.

補足

  • スワップ領域使用量はアクテビティモニタや vm_stats の Pageouts で確認できる。
$ vm_stat
Mach Virtual Memory Statistics: (page size of 4096 bytes)
Pages free:                             1617968.
Pages active:                           1123098.
Pages inactive:                          295638.
Pages speculative:                       683934.
Pages throttled:                              0.
Pages wired down:                        473140.
Pages purgeable:                         245419.
"Translation faults":                  10275868.
Pages copy-on-write:                     429818.
Pages zero filled:                      3576699.
Pages reactivated:                         4653.
Pages purged:                               133.
File-backed pages:                      1064238.
Anonymous pages:                        1038432.
Pages stored in compressor:                   0.
Pages occupied by compressor:                 0.
Decompressions:                               0.
Compressions:                                 0.
Pageins:                                 373701.
Pageouts:                                     0. ★
Swapins:                                      0.
Swapouts:                                     0.
  • pcom.apple.dynamic_pager.plist の内容は以下の通り。
$ sudo cat /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>EnableTransactions</key>
	<true/>
	<key>Label</key>
	<string>com.apple.dynamic_pager</string>
	<key>KeepAlive</key>
	<dict>
		<key>SuccessfulExit</key>
		<false/>
	</dict>
	<key>POSIXSpawnType</key>
	<string>Interactive</string>
	<key>ProgramArguments</key>
	<array>
		<string>/sbin/dynamic_pager</string>
		<string>-F</string>
		<string>/private/var/vm/swapfile</string>
	</array>
</dict>
</plist>

環境


参考

2017-10-11

Amazon Linux に Sysbench をインストールする

curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
sudo yum -y install sysbench

参考

2017-09-10

Oracle Database の PL/SQL を MySQL にどう移行するか

はじめに

Oracle Database の PL/SQL の MySQL への移行方法を説明します(MySQL 5.0 からストアドプロシージャに対応している)。

AWS Schema Conversion Tool (SCT) という GUI デスクトップアプリケーション(Windwos/Mac OS X/Linux版)をインストールし、移行元の Oracle Database に接続して自動的にPL/SQL を MySQL のルーチンに変換することができます。

SCT による変換方法は Oracle Database を Amazon Aurora に移行する方法 | Amazon Web Services ブログ をご覧ください。


移行先として適切なサービスを選ぶ

本題に入る前に Oracle Database からの移行先として MySQL、PostgreSQL、Redshift のどれが適切か説明します。

経験上、エンタープライズで Oracle Database を使っている場合は PostgreSQL が向いているケースが多いです。アクセスブロック数が少ないSQLのみで結合もネステッドループのみで問題ないシステムは MySQL が向いています。Exadata で OLTP(トランザクション) とOLAP(分析)を共存させている場合は PostgreSQL で OLTP、Redshift で OLAP(分析)という使い分けをオススメします。

MySQL が向いているケース
  • OLTP でシンプルでアクセスブロック数が少ないSQLが大半。
  • 結合はネステッドループのみで問題ない程度の軽い SQL のみ。
  • さらに結合も必要なく、キーのみにでアクセスするケースでは DynamoDB が向いています。
PostgreSQL が向いているケース
  • OLTP でも結合対象行数を絞れず HASH JOIN が必要な重いSQLが多い。
  • エンタープライズで Oracle Database を使っているシステムはこのケースが一番多い印象。
Redshift が向いているケース
  • Exadata で集計処理を投げていて Smart Scan を享受しているようなケースでは Redshift が向いている。
  • Exadata で OTLP(トランザクション処理)と分析の両方の用途で使っている場合は、OLTP は RDS で、分析は Redshift というように使い分けるアーキテクチャにする。

Oracle Database と MySQL のプロシージャ・ファンクションの構文の違い

SCT でプロシージャを変換した例

aws-database-migration-samples/generate_tickets.pls at master ? awslabs/aws-database-migration-samples ? GitHub を変換した例です。

  • Oracle Database(変換前)
procedure generate_tickets(P_event_id IN NUMBER) as
  CURSOR event_cur(P_ID NUMBER) IS
  SELECT id,location_id
  FROM   sporting_event
  WHERE  ID = P_ID;

  standard_price NUMBER(6,2);

BEGIN
  standard_price := DBMS_RANDOM.VALUE(30,50);

  FOR event_rec IN event_cur(P_event_id) LOOP
    INSERT /*+ APPEND */ INTO sporting_event_ticket(id,sporting_event_id,sport_location_id,seat_level,seat_section,seat_row,seat,ticket_price)
    SELECT sporting_event_ticket_seq.nextval
      ,sporting_event.id
      ,seat.sport_location_id
      ,seat.seat_level
      ,seat.seat_section
      ,seat.seat_row
      ,seat.seat
      ,(CASE
         WHEN seat.seat_type = 'luxury' THEN 3*standard_price
         WHEN seat.seat_type = 'premium' THEN 2*standard_price
         WHEN seat.seat_type = 'standard' THEN standard_price
         WHEN seat.seat_type = 'sub-standard' THEN 0.8*standard_price
         WHEN seat.seat_type = 'obstructed' THEN 0.5*standard_price
         WHEN seat.seat_type = 'standing' THEN 0.5*standard_price
      END ) ticket_price
    FROM sporting_event
       ,seat
    WHERE sporting_event.location_id = seat.sport_location_id
    AND   sporting_event.id = event_rec.id;
  END LOOP;
END;
  • MySQL(変換後)
    • コメントが入っている箇所は Oracle Database の構文に相当するものが MySQL になかった箇所で、この部分は自分でワークアラウンドを記述する必要があります。
CREATE PROCEDURE DMS_SAMPLE.GENERATE_TICKETS(IN par_P_EVENT_ID DOUBLE)
BEGIN
    DECLARE var$ID DOUBLE;
    DECLARE var$LOCATION_ID DOUBLE;
    DECLARE par_P_ID DOUBLE;
    DECLARE var_standard_price DECIMAL (6, 2);
    DECLARE done INT DEFAULT FALSE;
    DECLARE event_cur CURSOR FOR SELECT
        ID,a
        FROM SPORTING_EVENT
        WHERE ID = par_P_ID;
    DECLARE CONTINUE HANDLER FOR NOT FOUND
        SET done := TRUE
    /*
    [340 - Severity CRITICAL - MySQL doesn't support the SYS.DBMS_RANDOM.VALUE(NUMBER,NUMBER) function. Create a user-defined function.]
    standard_price := DBMS_RANDOM.VALUE(30,50)
    */;
    SET par_P_ID := par_P_event_id;
    OPEN event_cur;

    read_label:
    LOOP
        FETCH event_cur INTO var$ID, var$LOCATION_ID;

        IF done THEN
            LEAVE read_label;
        END IF;
        INSERT INTO SPORTING_EVENT_TICKET
            (ID, SPORTING_EVENT_ID, SPORT_LOCATION_ID, SEAT_LEVEL, SEAT_SECTION, SEAT_ROW, SEAT, TICKET_PRICE)
            SELECT
                aws_oracle_ext.sequence$nextval('SPORTING_EVENT_TICKET_SEQ', 'DMS_SAMPLE'), SPORTING_EVENT.ID, SEAT.SPORT_LOCATION_ID, SEAT.SEAT_LEVEL, SEAT.SEAT_SECTION, SEAT.SEAT_ROW, SEAT.SEAT, (CASE WHEN SEAT.SEAT_TYPE = 'luxury' THEN 3 * var_standard_price WHEN SEAT.SEAT_TYPE = 'premium' THEN 2 * var_standard_price WHEN SEAT.SEAT_TYPE = 'standard' THEN var_standard_price WHEN SEAT.SEAT_TYPE = 'sub-standard' THEN 0.8 * var_standard_price WHEN SEAT.SEAT_TYPE = 'obstructed' THEN 0.5 * var_standard_price WHEN SEAT.SEAT_TYPE = 'standing' THEN 0.5 * var_standard_price END) AS ticket_price
                FROM SPORTING_EVENT, SEAT
                WHERE SPORTING_EVENT.LOCATION_ID = SEAT.SPORT_LOCATION_ID AND SPORTING_EVENT.ID = var$ID;
    END LOOP;
    CLOSE event_cur;
END;


比較

CREATE PROCEDURE Statement

  • Converting stored procedures from Oracle to MySQL:
#OracleMySQL
1CREATE OR REPLACE PROCEDURE DROP PROCEDURE IF EXISTS and CREATE PROCEDURE
2param IN / OUT / IN OUT datatype Parameter definition IN / OUT / INOUT param datatype(length)
3IS / AS Removed
4Variable declaration is before BEGIN Variable declaration is after BEGIN
5END sp_name END

CREATE FUNCTION Statement

  • Converting user-defined functions from Oracle to MySQL:
#Oracle MySQL
1CREATE OR REPLACE FUNCTION DROP FUNCTION IF EXISTS and CREATE FUNCTION
2param IN / OUT / IN OUT datatype Parameter definition param datatype(length)
3RETURN datatype Return value RETURNS datatype(length)
4IS / AS Removed
5Variable declaration is before BEGIN Variable declaration is after BEGIN
6END func_name END

PL/SQL Statements

  • Converting PL/SQL statements and clauses from Oracle to MySQL:
#OracleMySQL
1variable datatype := value Variable declaration DECLARE variable datatype DEFAULT value
2variable := value Assignment statement SET variable = value
3CURSOR cur (params) IS SELECT Cursor declaration DECLARE cur CURSOR FOR SELECT
4Variable and cursor declarations can be mixed in any order Variable declarations must be before cursor and handlers
5FOR rec IN cursor LOOP Cursor loop OPEN cursor WHILE-FETCH-CLOSE
6IF THEN ELSIF ELSE END IF IF statement IF THEN ELSEIF ELSE END IF
7WHILE condition LOOP sql END LOOP A loop statement WHILE condition DO sql END WHILE
8EXIT WHEN condition Exit from a loop IF condition THEN LEAVE label END IF
  • EXCEPTION block:
#Oracle MySQL
1BEGIN stmts EXCEPTION … END Exception block structure BEGIN DECLARE HANDLER … stmts END
2WHEN DUP_VAL_ON_INDEX Duplicate key DECLARE EXIT HANDLER FOR SQLSTATE '23000'
3WHEN NO_DATA_FOUND No rows found DECLARE EXIT HANDLER FOR NOT FOUND
4WHEN OTHERS All exceptions DECLARE EXIT HANDLER FOR SQLEXCEPTION
http://www.sqlines.com/oracle-to-mysql#plsql-statements
  • パッケージ変数は MySQL ではセション変数(@)で代用できる。
  • 結果セットの返却は MySQL では SELECT 文を書くだけ。
  • %TYPE および %ROWTYPE データ型定義は MySQL にはない。

SCTを使った変換手順例

$ git clone https://github.com/awslabs/aws-database-migration-samples.git
  • Instant Client for Linux x86-64 (64-bit) から Oracle Instant Client をダウンロードする。
    • oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm
    • oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm
  • Oracle Instant Client をインストールする。
$ sudo rpm -ivh oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64.rpm
$ sudo rpm -ivh oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64.rpm
  • インストールされたファイルを確認する。
$ rpm -ql oracle-instantclient12.2-sqlplus-12.2.0.1.0-1.x86_64
/usr/bin/sqlplus64
/usr/lib/oracle/12.2/client64/bin/sqlplus
/usr/lib/oracle/12.2/client64/lib/glogin.sql
/usr/lib/oracle/12.2/client64/lib/libsqlplus.so
/usr/lib/oracle/12.2/client64/lib/libsqlplusic.so
$ rpm -ql oracle-instantclient12.2-basic-12.2.0.1.0-1.x86_64
/usr/lib/oracle/12.2/client64/bin/adrci
/usr/lib/oracle/12.2/client64/bin/genezi
/usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1
/usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1
/usr/lib/oracle/12.2/client64/lib/libipc1.so
/usr/lib/oracle/12.2/client64/lib/libmql1.so
/usr/lib/oracle/12.2/client64/lib/libnnz12.so
/usr/lib/oracle/12.2/client64/lib/libocci.so.12.1
/usr/lib/oracle/12.2/client64/lib/libociei.so
/usr/lib/oracle/12.2/client64/lib/libocijdbc12.so
/usr/lib/oracle/12.2/client64/lib/libons.so
/usr/lib/oracle/12.2/client64/lib/liboramysql12.so
/usr/lib/oracle/12.2/client64/lib/ojdbc8.jar
/usr/lib/oracle/12.2/client64/lib/xstreams.jar
$ vi ~.bashrc
export PATH=$PATH:/usr/lib/oracle/12.2/client64/bin
export NLS_LANG=American_America.UTF8
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/oracle/12.2/client64/lib
  • git をインストールする。
$ sudo yum -y install git
  • スクリプトを入手する。
$ git clone https://github.com/awslabs/aws-database-migration-samples.git
  • ソースの Oracle Database にスキーマとオブジェクトを作成する。
$ cd aws-database-migration-samples/oracle/sampledb/v1
$ sqlplus awsuser/******@******.******.ap-northeast-1.rds.amazonaws.com:1521/ORCL
SQL> install-rds.sql
  • SCT でソースとターゲットを指定して、変換する。

補足


参考

2017-08-01

SAP HANA Studio に表示される Database Resident Memory と HANA Used Memory の関係

一言で言うと、Database Resident Memory は HANA のプロセスが使っている物理メモリサイズで、HANA Used Memory は HANA から見て論理的に使っているメモリサイズ。つまり、Database Resident Memory - HANA Used Memory の差分はOSから見ると物理メモリを使っているけど、HANA から見ると空きメモリで利用可能な領域ということだと思う。

When memory is required for table growth or for temporary computations, the SAP HANA code obtains it from the existing memory pool. When the pool cannot satisfy the request, the HANA memory manager will request and reserve more memory from the operating system. At this point, the virtual memory size of the HANA processes grows.

Once a temporary computation completes or a table is dropped, the freed memory is returned to the memory manager, who recycles it to its pool, usually without informing Linux. Thus, from SAP HANA’s perspective, the amount of Used Memory shrinks, but the process’ virtual and resident sizes are not affected. This creates a situation where the Used Memory may even shrink to below the size of SAP HANA’s resident memory, which is perfectly normal.

The following illustration shows the relationship between physical memory, Linux virtual and resident memory, and SAP HANA’s pool and Used Memory indicators. Note how changes in Used Memory do not affect the processes’ virtual and resident sizes.

f:id:yohei-a:20170801235104p:image

https://www.edge-solutions.com/wp-content/uploads/2014/03/HANA_Memory_Usage_v2.pdf

以下のスライドで説明すると HANA Used Memory = Code and Stack + Table Data + Database Management で Allocated Memory Pool は含まない。Database Resident Memory > HANA Used Memory となる状況では、再利用可能な Allocated Memory Pool (Free) をプロセスが物理メモリを解放せずにそのままにしている(必要になったら上書き再利用する)と思われる。


Database Resident Memory の情報ソースは

3.1 - Hana Studio

3.1.1 - Database Resident

For the SAP Hana process:

SELECT 
   round(SUM(PHYSICAL_MEMORY_SIZE)/1024/1024/1024,2) AS "Database Resident Memory (Gb)" 
FROM 
  M_SERVICE_MEMORY
https://gerardnico.com/wiki/hana/memory/resident_memory

M_SERVICE_MEMORY システムビューの PHYSICAL_MEMORY_SIZE の合計で、

M_SERVICE_MEMORY System View

Detailed information on memory utilization by services.

Structure
Column nameData typeUnitDescription
PHYSICAL_MEMORY_SIZEBIGINTBytePhysical/resident memory size (operating system perspective)
no title

このシステムビューはおそらく /proc/[PID]/smaps などからプロセスが使用しているメモリサイズを取得しているのではないかと思う。

/proc/[pid]/smaps (since Linux 2.6.14)

This file shows memory consumption for each of the process's

mappings. (The pmap(1) command displays similar information,

in a form that may be easier for parsing.) For each mapping

there is a series of lines such as the following:

 00400000-0048a000 r-xp 00000000 fd:03 960637       /bin/bash
 Size:                552 kB
 Rss:460 kB
 Pss:100 kB
 Shared_Clean:        452 kB
 Shared_Dirty:          0 kB
 Private_Clean:         8 kB
 Private_Dirty:         0 kB
 Referenced:          460 kB
 Anonymous:             0 kB
 AnonHugePages:         0 kB
 ShmemHugePages:        0 kB
 ShmemPmdMapped:        0 kB
 Swap: 0 kB
 KernelPageSize:        4 kB
 MMUPageSize:           4 kB
 KernelPageSize:        4 kB
 MMUPageSize:           4 kB
 Locked:                0 kB
 ProtectionKey:         0
 VmFlags: rd ex mr mw me dw

The first of these lines shows the same information as is

displayed for the mapping in /proc/[pid]/maps. The following

lines show the size of the mapping, the amount of the mapping

that is currently resident in RAM ("Rss"), the process's

proportional share of this mapping ("Pss"), the number of

clean and dirty shared pages in the mapping, and the number of

clean and dirty private pages in the mapping.

proc(5) - Linux manual page

補足

Linux などの OS のメモリ管理はデマンドページングを行なっているものが多い。ユーザープロセスにメモリ領域を割当てた時点では仮想メモリのアドレス空間が割当てられるだけで物理メモリを使っておらず、メモリにデータを書いた時点で初めて物理メモリを使用する。ps コマンドで VSZ(Virtual Size in Kbytes) が仮想メモリサイズで、RSS(Resident Set Size) が物理メモリサイズ。RSS が実際に使っている物理メモリサイズになる。