[출처] http://theeye.pe.kr/entry/how-to-block-apache-with-proxy-remote-request

저는 단순히 DDOS공격인줄 알았습니다. IP는 정체를 알수 없이 전세계에서 들어오더군요. 사실상 끝나기를 기다리며 내 서버에는 사실상 영리목적의 사이트가 없는데 무엇이 목적일까 고민하게 되었습니다.

우선 쌓이는 로그가 매우 특이한것을 알수 있었습니다. 로그는 대충 다음과 같은 형식이었습니다.

202.109.175.224 - - [17/Apr/2009:21:17:39 +0900] "GET http://www.dfwater.com/Index.asp HTTP/1.1" 503 28 "http://www.dfwater.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 5.1)"
84.16.227.121 - - [17/Apr/2009:21:17:35 +0900] "GET http://www.google.com/ie?q=puts+inurl:?p%3D&hl=en&num=100&start=200&sa=N HTTP/1.0" 302 335 "http://www.google.com/ie?q=puts+inurl:?p%3D&hl=en&num=100&start=200&sa=N" "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"
64.91.72.166 - - [17/Apr/2009:21:17:39 +0900] "CONNECT 205.188.251.26:443 HTTP/1.0" 200 - "-" "-" 61.160.211.12 - - [17/Apr/2009:21:17:36 +0900] "GET http://www.kiss888mu.cn HTTP/1.1" 500 3847 "http://www.baidu.com" "Mozilla/4.0 (compatible; MSIE 6.0; Windows 5.1)"
118.69.166.3 - - [17/Apr/2009:21:17:39 +0900] "GET http://69.147.112.211/config/isp_verify_user?l=mmg&p=0011 HTTP/1.0" 200 26 "-" "-"
208.70.78.177 - - [17/Apr/2009:21:17:36 +0900] "GET http://www.google.com/ie?as_q=inurl:/guestbook.html+tampa+fl+gay+life+and+dating&num=100&hl=en HTTP/1.0" 302 355 "http://www.google.com/ie?as_q=inurl:/guestbook.html+tampa+fl+gay+life+and+dating&num=100&hl=en" "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050224 Firefox/1.0+"
78.30.203.105 - - [17/Apr/2009:21:17:39 +0900] "GET http://inmarket73.ru/forum/index.php?s=fb2bade970f814c6d66c67f414a2328b&act=Reg&CODE=image&rc=35f728107e6ae6292a22c4e6f16634ac&p=3 HTTP/1.0" 200 68 "http://inmarket73.ru/forum/index.php?act=Reg&CODE=image&rc=7f430230e31d334872d1b5136a57b9ce&p=1" "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1)"
94.76.199.2 - - [17/Apr/2009:21:17:36 +0900] "GET http://superschurke.de/comments/feed/ HTTP/1.1" 404 809 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"


로그가 좀 지저분 합니다만 형식이 다음과 같다는것만 보시면 됩니다. 요청이 GET 메서드 이후에 http로 시작하는 것을 알수 있습니다. 그것도 전혀 쌩뚱 맞은 도메인과 호스트에 요청을 합니다.

이것이 왜 이상하냐면 보통의 브라우저는 요청을 할때 다음과 같이 합니다. theeye.pe.kr/index.html의 요청이 있다면 DNS에 질의 하여 theeye.pe.kr 도메인의 호스트 IP를 알아낸 이후에 그곳에 접속하여 GET /index.html 과 같은 방법으로 요청을 하게 됩니다.

위와 같은 방법은 마치 여의도에 가서 "롯데월드가 어딧나요?" 라고 물어보는 꼴이 되는 것입니다.

왜 저런 요청이 자꾸 들어오는 것인지 궁금하여 서버에 다음과 같이 테스트를 해보았습니다.

telnet theeye.pe.kr 80
GET http://www.naver.com

자, 상식적으로 잘못된 요청이라고 나와야 하지만 정상적으로 페이지가 출력됩니다. 아니 왜 내 서버에서 엉뚱한 사이트의 요청을 처리해 주는 것이지!?

이제 여의도에 가서 "롯데월드가 어딧나요?" 라고 물었더니 상대방이 자기 차에 태워 롯데월드에 데려다 주었습니다.

친절한 사람이군요;;; 근데 문제가, 이걸 악용해서 소문이 나서 세상의 모든 사람이 이 친절한 사람에게 와서 자신이 가고싶은 곳이 어딧는지를 물어본다는 것이 문제가 됩니다.

서버가 엉뚱한 요청을 받아 대리 요청후에 결과를 되돌려 주는 문제는 일전의 Proxy설정의 잘못이었습니다.

ProxyAJP설정을 별다른 보안 절차 없이 설정하게 되면 이 세상 모든 http 요청의 IP세탁 시스템으로 둔갑되어질 수 있습니다.

이문제를 해결하기 위해서는 간단하게 Proxy 요청은 로컬호스트에서만 가능하게 설정하시면 됩니다.

<Proxy *>
Order Deny,Allow
Deny from all
Allow from localhost
</Proxy>

간단하게 해결되었죠? Proxy 설정을 하시고 서버를 운영하시는 분들은 다른 호스트로의 요청을 해보시기 바랍니다.

에러없이 요청이 정상처리 된다면, 이제 표적이 되기전에 설정을 조금 손보시기 바랍니다.

첨언 : 추가로 로그들을 쭉 분석해 봤는데, 위와 같은 방법을 사용하는 이유는 특정 사이트의 검색요청을 계속하여 검색랭킹을 올린다거나, 추천사이트의 어뷰징 혹은 사이트 페이지뷰를 높이는데 사용되어지는 듯 싶습니다.

블로그 이미지

유효하지않음

,
[출처] http://eyecandyzero.tistory.com/tag/404, http://levin01.tistory.com/575

web.xml에 error-page 설정후 적용되지 않을경우


	
	    java.lang.throwable
	    /common/error/error.ng
	
	
		java.lang.NullPointerException
		/common/error/error.ng
	
	
		java.lang.Exception
		/common/error/error.ng
	
	
	    404
	    /common/error/error.ng
	
	
	    400
	    /common/error/error.ng
	
	
	    500
	    /common/error/error.ng
	



IE 가 http 404 status 를 만나게 되면 대부분 로컬에 저장되어있는 다음 페이지를 강제로 보여주더군요
res://C:\WINNT\system32\shdoclc.dll/http_404.htm

<%@ page contentType="text/html; charset=MS949" %>
<%
	response.setStatus(HttpServletResponse.SC_OK); //200
	
	/*
	Object exObj = req.getAttribute("javax.servlet.error.exception");
	String uri = "";
	
	if(uriObj != null)
	{
		uri = uriObj.toString();
		
		out.println(uri);
		out.println("
"); } */ out.print(request.getAttribute("javax.servlet.error.status_code")); out.print("
"); out.print(request.getAttribute("javax.servlet.error.exception_type")); out.print("
"); out.print(request.getAttribute("javax.servlet.error.message")); out.print("
"); out.print(request.getAttribute("javax.servlet.error.exception")); out.print("
"); out.print(request.getAttribute("javax.servlet.error.request_uri")); %>

ERROR PAGE에서 활용하는 방법

${requestScope['javax.servlet.error.status_code']}

javax.servlet.error.status_code:
        에러 상태 코드를 말해 주는 정수
javax.servlet.error.exception_type
        에러가 생기게 된 예외 형을 지적해 주는 클래스 인스턴스
javax.servlet.error.message
        예외 메시지를 말해주는 스트링이며, 예외 컨스트럭터로 보내어 진다.
javax.servlet.error.exception
        실제 예외가 없어지면 버릴 수 있는 객체이다.
javax.servlet.error.request_uri
        문제를 일으킨 리소스의 URI를 말해주는 스트링이다.

javax.servlet.error.servlet_name

 

Throwable e = (Throwable)request.getAttribute("javax.servlet.error.exception");
Throwable e1 = (Throwable)request.getAttribute("javax.servlet.jsp.jspException");

 

오류 페이지에서만 쓸 수 있는 객체 : exception

<%@ page isErrorPage="true" %>
${pageContext.exception}


오류 발생 후 오류 페이지로 이동하지 않고 자체 페이지에서 해결하기 : <c:catch>

<c:catch>
   <% int x = 10/0; %>
   // 에러가 발생하면 다음을 실행하지 않고 </c:catch>로 곧장 이동한다.
</c:catch>


exception을 속성으로 만들어 에러 메시지 읽기

<c:catch var="myException">
   ...
</c:catch>
${myException.message}
// 타입이 Throwable이니 message프로퍼티가 있음

블로그 이미지

유효하지않음

,

vim 단축키 모음

OS 2009. 4. 7. 20:42

PHPSCHOOL 토크박스에 있던거 괜찮아서 추가했습니다.

블로그 이미지

유효하지않음

,
==> 본인의 글 입니다. 이 글을 다른곳에 게재하는 경우 본문의 출처를 밝혀주시기 바람니다.

거래처 솔라리스인 관계로 리눅스에서 작업했던 bash쉘 기능이 전부 먹히지 않아
그냥 Perl 스크립트로 만들어 보았습니다..

file: ora_backup.pl
#!/usr/bin/perl

use DBI;
use Time::Local;
use Error qw(:try);
use Archive::Zip qw(:ERROR_CODES :CONSTANTS);

BEGIN
{
	$ENV{ORACLE_OWNER}		= "oracle9";
	$ENV{ORACLE_BASE}		= "/home/$ENV{ORACLE_OWNER}";
	$ENV{ORACLE_HOME}		= "$ENV{ORACLE_BASE}/product/9i";
	$ENV{TNS_ADMIN}			= "$ENV{ORACLE_HOME}/network/admin";
	$ENV{ORA_NLS33}			= "$ENV{ORACLE_HOME}/ocommon/nls/admin/data";
	$ENV{ORACLE_SID}		= "NEXTBSC";
	$ENV{ORACLE_TNSNAME}	= "NEXTBSC";
	$ENV{NLS_LANG}			= "KOREAN_KOREA.KO16MSWIN949";
	$ENV{NLS_NCHAR}			= "KOREAN_KOREA.UTF8";
	$ENV{LD_LIBRARY_PATH}	= "$ENV{ORACLE_HOME}/lib:$ENV{ORACLE_HOME}/lib32:$ENV{ORACLE_HOME}/rdbms/demo:$ENV{ORACLE_HOME}/oracm/lib:/lib:/usr/lib:/usr/local/lib";
	$ENV{LD_RUN_PATH}		= "$ENV{ORACLE_HOME}/lib";
	$ENV{NLS_DATE_FORMAT}	= "YYYYMMDD";
	$ENV{TEMPDIR}			= "/tmp";
	$ENV{THREADS_FLAG}		= "native";
}

=comment
foreach my $key(keys %ENV)
{
	print $key."=". $ENV{$key}."\n";
}
=cut

##-------------------------------------------------------------------------------------------------------
## 삭제할 파일 일자 정의(3일전)
##-------------------------------------------------------------------------------------------------------
($year, $month, $day) = (localtime(time - (60*60*24*3)))[5,4,3];
my $rmdate			  = sprintf("%04d%02d%02d", $year+1900, $month+1, $day);


##-------------------------------------------------------------------------------------------------------
##백업할 파일 일자 정의(당일)
##-------------------------------------------------------------------------------------------------------
($year, $month, $day) = (localtime(time))[5,4,3];
my $date			  = sprintf("%04d%02d%02d", $year+1900, $month+1, $day);
#my $date			  = sprintf("%02d", $day);


##-------------------------------------------------------------------------------------------------------
## 기본 변수 선언. 
##-------------------------------------------------------------------------------------------------------
my $user		= "qes_bsc";
my $bakdir		= "/data1/oracle9i_dmp_files/";
my $fullpath	= $bakdir.$date		."_". $user ."_full.zip";
my $onepath		= $bakdir.$date		."_". $user ."_one.zip";
my $rmfullpath	= $bakdir.$rmdate	."_". $user ."_full.zip";
my $rmonepath	= $bakdir.$rmdate	."_". $user ."_one.zip";
my @nums		= (0..30);


#-------------------------------------------------------------------------------------------------------
# FULL 백업 ....
#-------------------------------------------------------------------------------------------------------
print "\nFULL 백업중.....\n";
my	$command  = "$ENV{ORACLE_HOME}/bin/exp $user/$user\@$ENV{ORACLE_TNSNAME} grants=y ";
	$command .= " file=(";
	for(@nums)
	{
		$command .= $bakdir . $user ."_full_". sprintf("%02s", $_) .".dmp,";
	}
	$command  = substr($command, 0, length($command)-1);
	$command .= " )";
	$command .= " filesize=2G";
	$command .= " log=". $bakdir . $user .".log";

system $command;


##-------------------------------------------------------------------------------------------------------
## 테이블 단위 백업....
##-------------------------------------------------------------------------------------------------------
try
{
	print "\n테이블 단위 백업중.....\n";
	my $conn	= DBI->connect("DBI:Oracle:NEXTBSC", $user, $user, {AutoCommit => 0, RaiseError => 1, PrintError => 0 }) || die "Error :$DBI::errstr";
	my $SQL		= "SELECT tname FROM tab WHERE tname NOT LIKE 'BIN%' ";
	my $stmt	= $conn->prepare($SQL);
	$stmt->execute();

	while(@row = $stmt->fetchrow_array)
	{
		my $command = "";

		if(@row["TNAME"] == "NG01_REPORT_INFO")
		{
			$command  = "$ENV{ORACLE_HOME}/bin/exp qes_bsc/qes_bsc\@$ENV{ORACLE_TNSNAME} grants=y ";
			$command .= " tables=". @row["TNAME"];
			$command .= " file=(";
			for(@nums)
			{
				$command .= $bakdir . @row["TNAME"] ."_one_". sprintf("%02s", $_) .".dmp,";
			}
			$command  = substr($command, 0, length($command)-1);
			$command .= " )";
			$command .= " filesize=2G";
		}
		else
		{
			$command  = "$ENV{ORACLE_HOME}/bin/exp qes_bsc/qes_bsc\@$ENV{ORACLE_TNSNAME} grants=y ";
			$command .= " tables=". @row["TNAME"];
			$command .= " file=". $bakdir . @row["TNAME"] ."_one_". ".dmp";
		}
		system $command;
	}

	$stmt->finish;
	$conn->disconnect;
}
catch Error with
{
	my $ex = shift;
	print $ex;
}
finally 
{
	#close_the_garage_door_already();
};


##-------------------------------------------------------------------------------------------------------
## FULL 백업 압축....
##-------------------------------------------------------------------------------------------------------
try
{
	opendir(DIR, $bakdir);
	@files = grep(/_full_\d{2}/, readdir(DIR));
	print $bakdir.@files;
	closedir(DIR);

	if(@files > 0)
	{
		my $zip		= Archive::Zip->new();
		my $comp	= $zip->addDirectory($date);
		$comp->desiredCompressionMethod(COMPRESSION_DEFLATED);
		$comp->desiredCompressionLevel(COMPRESSION_LEVEL_BEST_COMPRESSION);
		print "FULL 백업을 압축중입니다.....!!!\n";

		foreach my $file(sort @files)
		{
			print $file. "\n";
			$comp	= $zip->addFile($bakdir . $file, $date ."/". $file) || die 'write error';
			$check	= true;
		}
		$zip->writeToFileNamed($fullpath) == AZ_OK;
		system "split -b 680m ". $fullpath ." ". $fullpath.".";
	}
}
catch Error with
{
	my $ex = shift;
	print $ex;
}
finally 
{
	#close_the_garage_door_already();
};


##-------------------------------------------------------------------------------------------------------
## 테이블 단위 압축....
##-------------------------------------------------------------------------------------------------------
try
{
	opendir(DIR, $bakdir);
	@files = grep(/_one_(\d{2})?/, readdir(DIR));
	closedir(DIR);
	print $bakdir.@files;

	if(@files > 0)
	{
		my $zip		= Archive::Zip->new();
		my $zip		= Archive::Zip->new();
		my $comp	= $zip->addDirectory($date);
		$comp->desiredCompressionMethod(COMPRESSION_DEFLATED);
		$comp->desiredCompressionLevel(COMPRESSION_LEVEL_BEST_COMPRESSION);
		print "\n테이블 단위 백업을 압축중입니다.....!!!\n";

		foreach my $file(sort @files)
		{
			print $file. "\n";
			$comp	= $zip->addFile($bakdir . $file, $date ."/". $file) || die 'write error';
		}
		$zip->writeToFileNamed($onepath) == AZ_OK;
		system "split -b 680m ". $onepath ." ". $onepath.".";
	}
}
catch Error with
{
	my $ex = shift;
	print $ex;
}
finally 
{
	#close_the_garage_door_already();
};


##-------------------------------------------------------------------------------------------------------
## 삭제할 파일
##-------------------------------------------------------------------------------------------------------
system "rm -f ". $rmfullpath;
system "rm -f ". $rmonepath;
system "rm -f ". $bakdir ."*.dmp";


__END__
##-------------------------------------------------------------------------------------------------------
## 실행전에 필용한 팩키지 목록들....
##-------------------------------------------------------------------------------------------------------
##perl -e "use Archive::Zip"
##perl -MCPAN -e "install DBD::Oracle"
##perl -MCPAN -e "install Archive::Zip"
##perl -MCPAN -e shell
##cpan>i /archive::zip/
##cpan>install Archive::Zip
##cpan>quit
##windows --> copy /b XXXX_full_zip.aa + XXXX_full_zip.ab  XXXX_full.zip
##solaris --> cat XXXX_full_zip.?? >  XXXX_full.zip
##linux   --> XXXX_full_zip.* >  XXXX_full.zip

##__author__  = "park17@gmail.com"
##__version__ = "0.1"
##__date__    = "2007-09-29"
##__file__    = "ora_backup.pl"

2G가 이상되면 unzip 명령어가 먹지 않네요..
64비트 옵션을 주고 컴파일 하면 된다고 하는데 안되더라구요..
그래서 귀찮아서 그냥 이것도 Perl 스크립트로 만들었습니다.

file: unzip.pl

#!/usr/bin/perl

use strict;
use Archive::Zip qw(:ERROR_CODES);

my $zip = Archive::Zip->new();
my $zipName = shift(@ARGV);

if($zip->read($zipName) != AZ_OK)
{
    die "Read of $zipName failed\n";
}
else
{
    foreach my $member($zip->members())
    {
        print $member->fileName(), ", ", $member->uncompressedSize(), ":", $member->compressedSize(), "\n";
        $zip->extractMember($member->fileName());
    }
}
블로그 이미지

유효하지않음

,
먼저 오라클 클럽에 올라와 있는 글을 조금 참조했음을 알려드립니다.
 ==> 본인의 글 입니다. 이 글을 다른곳에 게재하는 경우 본문의 출처를 밝혀주시기 바람니다. 

procedures_backup.sql
---------------------------------------
SET SERVEROUTPUT ON SIZE 1000000
SET ECHO OFF VERIFY OFF FEEDBACK OFF TRIMSPOOL ON PAGES 0 LINES 512
SET TERMOUT OFF
SET TERMOUT ON
!rm -rf './proc_backup';
!mkdir './proc_backup';
PROMPT
PROMPT PROCEDURES export Start...!!!!
PROMPT
SET TERMOUT OFF
SPOOL procedures_exp.sql
PROMPT SET ECHO OFF VERIFY OFF FEEDBACK OFF TRIMSPOOL ON TERMOUT OFF PAGES 0
--PROMPT SET LINESIZE 512;
--LINES 512

DECLARE
    TYPE objectElements IS VARRAY(5) OF VARCHAR2(20);
    VObjectType objectElements	:= objectElements('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TYPE');
    vObjectExt  objectElements	:= objectElements('prc', 'spc', 'bdy', 'fnc', 'tps');
	vObjectName	VARCHAR2(50)	:= '';
	vExportDir	VARCHAR2(20)	:= './proc_backup/';
	--vFileHandle	UTL_FILE.FILE_TYPE;
    
    CURSOR cur_procedures(v_object_type VARCHAR2)
    IS
        SELECT  name  --, DBMS_METADATA.GET_DDL(v_object_type, name) text
        FROM    USER_SOURCE
        WHERE   TYPE = v_object_type
        GROUP   BY name;

	--
	-- DBA 권한시 수정하여 사용.(procedures_dump.sql 파일도 수정) 
	--
	/*
    CURSOR cur_procedures(v_owner VARCHAR2, v_object_type VARCHAR2)
    IS
		SELECT  object_name name --, DBMS_METADATA.GET_DDL(v_object_type, object_name, owner) 
		FROM	dba_objects
		WHERE	owner	 	= v_owner
		AND		object_type = v_object_type
		ORDER BY owner
	*/
        
BEGIN
	--DBMS_OUTPUT.ENABLE('10000000000');
     
	FOR i IN VObjectType.FIRST .. VObjectType.LAST
    LOOP
        FOR list_procedures IN cur_procedures(VObjectType(i))
        LOOP
			vObjectName := LOWER(list_procedures.name || '.' || vObjectExt(i));
			DBMS_OUTPUT.put_line('SET TERMOUT ON');
			DBMS_OUTPUT.put_line('PROMPT ' || VObjectType(i) || ' -->> ' || vExportDir || vObjectName);
			DBMS_OUTPUT.put_line('SET TERMOUT OFF');
			DBMS_OUTPUT.put_line('spool ' || vExportDir || vObjectName);
			DBMS_OUTPUT.put_line('@procedures_dump ' || VObjectType(i) || ' ' || list_procedures.name);
			DBMS_OUTPUT.put_line('spool off');

			--vFileHandle := UTL_FILE.fopen(vExportDir, list_procedures.name || '.' || vObjectExt(i), 'W'); 
			--UTL_FILE.put_line(vFileHandle, list_procedures.text); 
			--UTL_FILE.fclose(vFileHandle); 
        END LOOP;
	END LOOP;
	
/*
EXCEPTION 
	WHEN NO_DATA_FOUND THEN 
		DBMS_OUTPUT.put_line('NO_DATA_FOUND');
		UTL_FILE.fclose(vFileHandle); 
		NULL;
	WHEN UTL_FILE.INVALID_PATH THEN 
		DBMS_OUTPUT.put_line('UTL_FILE.INVALID_PATH'); 
		UTL_FILE.fclose(vFileHandle); 
	WHEN UTL_FILE.READ_ERROR THEN 
		DBMS_OUTPUT.put_line(' UTL_FILE.READ_ERROR'); 
		UTL_FILE.fclose(vFileHandle); 
	WHEN UTL_FILE.WRITE_ERROR THEN 
		DBMS_OUTPUT.put_line('UTL_FILE.WRITE_ERROR'); 
		UTL_FILE.fclose(vFileHandle); 
	WHEN OTHERS THEN 
		DBMS_OUTPUT.put_line('OTHER STUFF'); 
		UTL_FILE.fclose(vFileHandle); 
*/
END;
/
SPOOL OFF;
@procedures_exp.sql;

SET TERMOUT ON
PROMPT
PROMPT PROCEDURES export End...!!!!
PROMPT
SET TERMOUT OFF

QUIT;

procedures_dump.sql 
---------------------------------------
SET SERVEROUTPUT ON SIZE 1000000
SET HEAD OFF VERIFY OFF
SET LONG 1000000
COL TEXT FORMAT A132;
	SELECT  TRIM(DBMS_METADATA.GET_DDL('&1', name)) text
	FROM    USER_SOURCE
	WHERE   type = '&1'
	AND		name = '&2'
	GROUP   BY name;

/*
	SELECT  TRIM(DBMS_METADATA.GET_DDL('&2', object_name, '&1')) text
	FROM    dba_objects
	WHERE   owner       = '&1'
	AND     object_type = '&2'
	ORDER BY owner
*/
PROMPT /
블로그 이미지

유효하지않음

,

DBMS_scheduler

Database/Oracle 2009. 3. 12. 10:02

운영체제에서 CRON과 같은 명령어를 통해 사용자가 주기적, 비주기적으로 실행하는 프로그램을 자동으로 실행해주는 기능을 수행하듯이
오라클 RDBMS 기반의 시스템에서는 다양한 stored procedure, package, java class등의 프로그램을 데이터베이스 내에 생성하고, 필요에 따라 실행하게 된다.

이러한 DB 기반의 프로그램을 데이터베이스 네에서 주기적, 비주기적으로 실행해야 하는 경우, 스케쥴러 기능을 사용할 수 있다.

이 기능을 사용하기 위해서는 해당 사용자는 create any job 시스템 권한을 부여 받아야 한다.

DBMS_scheduler 패키지는 4가지 구성요소를 가진다.
program 스케쥴러에 의해 실행될 DB 프로그램
job 스케쥴러에 등록된 작업 유형
schedule 등록된 작업의 작업 일정
window 수행될 작업에 할당될 시스템 자원에 대한 정보

begin
	dbms_scheduler.create_program
	(
		program_name   => 'test_scheduler',
		program_action => '/export/home/work/aaa.exe',
		program_type   => 'executable'
	);
end;
/
새롭게 생성한 프로그램은 scheduler에 의해 사용 가능하도록 활성화 상태이어야 한다.
SQL> execute dbms_scheduler.enable('test_scheduler');

또는 다음과 같이 비활성화시킬 수 도 있다. 
SQL> execute dbms_scheduler.disable('test_scheduler'); 

scheduler 내에 생성되어 있는 프로그램을 삭제한다.
begin
	dbms_scheduler.drop_program
	(
		program_name   => 'test_scheduler',
		force          => false
	);
end;
/
다음은 실행할 프로그램의 스케쥴 계획을 생성한다. 스케쥴 이름과 실행될 시각, 종료시각, 실행주기등을 작성할 수 있다.
begin
	dbms_scheduler.create_schedule
	(
		program_name   => 'hourly_schedule',
		start_date     => systimestamp,
		end_date       => systimestamp + interval '30' day,
		repeat_interval => 'freq=hourly; interval=4',
		comments        => 'every 4 hours'
	); 
end;
/ 
create_job 프로시져를 이용하면 스케줄과 함깨 실행할 SQL 문장 또는 PL/SQL 블럭을 등록할 수 있다.
begin
	dbms_scheduler.create_job
	(
		job_name   => 'my_emp_job1',
		job_type   => 'PLSQL_BLOCK',
		job_action => 'insert into emp values(7987, "SALLY","ANALYST",
		null,null,null,null,null);',
		start_date     => '09/07/23 17:16:51.927000+09:00',
		repeat_interval => 'freq=daily; interval=2',
		comments        => 'my new job'
	); 
end;
/ 
다음은 실행될 스케쥴 job을 삭제하는 방법이다.
begin
	dbms_scheduler.drop_job
	(
		job_name   => 'my_emp_job1',
		force      => false
	);
end;
/ 
이제, check_test라는 PL/SQL 블럭을 생성해서 스케쥴러에 등록한 후, 자동으로 실행해 보자.
create or replace procedure check_test
IS
	v_no     number(4);
	v_name   varchar2(13) := null;
BEGIN
	select	empno, ename into v_no, v_name from scott.emp
	where	empno =7934;
	dbms_output.put_line(v_no||'  '||v_name);
END;
/

BEGIN
	dbms_scheduler.create_job
	(
		job_name    => 'my_emp_job2',
		job_type    => 'PLSQL_BLOCK',
		job_action  => 'BEGIN check_test(); END;',
		schedule_name => 'hourly_schedule'
	);
END;
/
execute dbms_scheduler.enable('my_emp_job2');
scheduler에 의해 활성화된 my_emp_job2를 스케쥴링한다.
execute dbms_scheduler.run_job('my_emp_job2');

BEGIN
	DBMS_SCHEDULER.DROP_JOB
	(
		job_name   => 'my_emp_job2';
		force      => false
	);
END;
/
이번에는 운영체제상에 존재하는 실행파일을 스케쥴러에 등록한 후 자동으로 실행하는 예제
begin
	dbms_scheduler.create_job
	(
		job_name     => 'my_emp_job3',
		job_type     => 'executable',
		job_action   => '/export/home/work/aaa',
		start_date   => systimestamp,
		repeat_interval => 'freq=daily; ingterval=2',
		end_date     => systimestamp + interval '30' day
	);
end;
/

execute dbms_scheduler.enable ('my_emp_job3');
execute dbms_scheduler.run_job('my_emp_job3');
BEGIN
dbms_scheduler.drop_job
(
	job_name => 'my_emp_job3',
	force    => false
);
END;
/
이번에는 실행될 프로그램에 자원관리 기능을 적용하는 방법
begin
	dbms_scheduler.create_window
	(
		window_name   =>'my_window100',
		schedule_name => 'hourly_schedule',
		resource_plan => 'internal_plan',
		duration      => interval '160' minute,
		comments      => 'My window'
	);
END;
/

execute dbms_scheduler.enable ('my_wondow100');
execute dbms_scheduler.run_job('my_emp_job2');
오라클 자료사전의 scheduler와 관련된 자료
col comments format a35
col table_name format a35

select	table_name, comments from dictionary
where	table_name like 'DBA%SCHEDULER%'
order	by table_name;
TABLE_NAME                          COMMENTS
----------------------------------- -----------------------------------
DBA_SCHEDULER_CHAINS                All scheduler chains in the database

DBA_SCHEDULER_CHAIN_RULES           All rules from scheduler chains in the database

DBA_SCHEDULER_CHAIN_STEPS           All steps of scheduler chains in the database

DBA_SCHEDULER_CREDENTIALS           All scheduler credentials in the database

DBA_SCHEDULER_GLOBAL_ATTRIBUTE      All scheduler global attributes
DBA_SCHEDULER_JOBS                  All scheduler jobs in the database
DBA_SCHEDULER_JOB_ARGS              All arguments with set values of all scheduler jobs in the database

DBA_SCHEDULER_JOB_CLASSES           All scheduler classes in the database

DBA_SCHEDULER_JOB_LOG               Logged information for all scheduler jobs

DBA_SCHEDULER_JOB_ROLES             All scheduler jobs in the database by database role

DBA_SCHEDULER_JOB_RUN_DETAILS       The details of a job run
DBA_SCHEDULER_PROGRAMS              All scheduler programs in the database

DBA_SCHEDULER_PROGRAM_ARGS          All arguments of all scheduler programs in the database

DBA_SCHEDULER_REMOTE_DATABASES      List of registered remote databases for jobs

DBA_SCHEDULER_REMOTE_JOBSTATE       Remote state of all jobs originating from this database

DBA_SCHEDULER_RUNNING_CHAINS        All steps of all running chains in the database

DBA_SCHEDULER_SCHEDULES             All schedules in the database
DBA_SCHEDULER_WINDOWS               All scheduler windows in the database

DBA_SCHEDULER_WINDOW_DETAILS        The details of a window
DBA_SCHEDULER_WINDOW_GROUPS         All scheduler window groups in the database

DBA_SCHEDULER_WINDOW_LOG            Logged information for all scheduler windows

DBA_SCHEDULER_WINGROUP_MEMBERS      Members of all scheduler window groups in the database


22 rows selected.

SQL>
블로그 이미지

유효하지않음

,

예전에 database.sarang.net의 오라클 게시판에 DBMS_JOB을 이용해 원하는 작업을 08시, 14시, 20시에 실행시키는 방법을 묻는 질문이 올라왔다. 작업 간격이 규칙적일 때는 문제가 간단하지만 원하는 시간 간격이 불규칙하므로 그냥 JOB을 세 개 등록하면 어떻겠냐고 답했더니 이번에는 이 작업을 평일에만 실행시키게 하고 싶다고 했다. 즉 평일 08시, 14시, 20시에 작업이 실행되도록 하고 싶다는 것이었다. 그럼 문제를 풀기 전에 DBMS_JOB.SUBMIT 프로시저를 살펴보자. DBMS_JOB을 이용해 JOB을 등록시키려면 SUBMIT 프로시저를 사용해야 한다. 파라미터 중 next_date와 interval를 통해 작업 실행 시각을 조절할 수 있다.
DBMS_JOB.SUBMIT (
     job       OUT BINARY_INTEGER,
     what      IN  VARCHAR2,
     next_date IN  DATE DEFAULT sysdate,     -- 실행할 시각
     interval  IN  VARCHAR2 DEFAULT 'null',  -- 다음 실행될 시점을 계산할 수식
     no_parse  IN  BOOLEAN DEFAULT FALSE,
     instance  IN  BINARY_INTEGER DEFAULT any_instance,
     force     IN  BOOLEAN DEFAULT FALSE);
next_date의 디폴트 값은 sysdate이므로 값을 주지 않으면 등록 즉시 실행된다. 그 다음 실행 시각은 JOB이 실행되기 직전 interval에 지정된 수식을 이용해 계산한다. (interval이 NULL일 경우는 작업이 한 번만 실행된다.) 파라미터 이름이 interval이기는 하지만 실제 의미는 interval이 아니라 "다음 실행될 시점을 계산할 수식"인 것이다. 만약 어떤 작업을 1시간에 1번씩 실행시키고 싶다면 interval을 'sysdate+1/24'로 주면 된다. 작업을 시작하기 전에 sysdate+1/24를 통해 다음 실행할 시각을 구하면 작업 시작 시간으로부터 1시간 후인 시각이 된다. 다음 작업 시작 시각을 알고 싶으면 ALL_JOBS의 NEXT_DATE 컬럼을 조회해 확인할 수 있다.

interval 작업 주기
'sysdate + 1/24' 1시간에 1번
'sysdate + 1' 1일에 1번
'sysdate + 7' 7일(일주일)에 한번

그런데 위와 같이 하면 작업 주기만 지정한 것일 뿐이다. 특정 시각에 JOB을 실행시키려면 다음과 같이 하면 된다.

interval 작업 시각
'trunc(sysdate) + 1 + 1/24' 매일 01시에 작업 실행
'trunc(sysdate, ''D'') + 7' 매주 일요일 00시에 작업 실행

interval 파라미터는 문자열로 주어야 하므로 수식 내에 따옴표(single quotation)이 있으면 따옴표를 두 개 써줘야 하는 것에 유의해야 한다. interval 수식이 복잡할 때는 확인하기가 어려울 수 있는데, 그럴 때는 interval 수식으로 직접 쿼리를 작성해 확인할 수 있다.
select trunc(sysdate, 'D') + 7 from dual;
이제 다음과 같이 다양한경우에 대한 interval을 구해보자.
  1. 매주 토요일 새벽 1시에 실행
  2. 매월 1일 새벽 0시에 실행
  3. 매월 말일 밤 11시에 실행
  4. 평일(월화수목금) 밤 10시에 실행
  5. 불규칙한 시각, 8시, 14시, 20시에 한번씩
...
next_date=>to_date('2007102701','YYYYMMDDHH24'),
interval=>'sysdate + 7'
...
월초나 월말의 경우는 add_months나 last_day를 이용해 구하면 된다.
-- 매월1일 새벽 0시 작업 실행
...
next_date=>add_months(trunc(sysdate,'MM'),1),
interval=>'add_months(trunc(sysdate,''MM''),1)'


-- 매월 말일 밤 11시에 작업 실행
...
next_date=>last_day(trunc(sysdate))+23/24,
interval=>'last_day(trunc(sysdate)+1)+23/24'  -- 말일+1일은 다음달 1일
...
평일만 실행되도록 하기 위해서는 interval이 좀더 복잡해진다.
...
interval=>'trunc(sysdate) + decode(to_char(sysdate,''D''), ''6'', 3, ''7'', 2, 1) + 22/24'
...
요일을 구한 다음 토요일(to_char(sysdate,'D')='6')에는 작업 후 3일 후에, 일요일(to_char(sysdate,'D')='7')에는 작업 후 2일 후에, 평일에는 자업 후 1일 후에 작업이 다시 시작되도록 하면 된다. 이를 위해 DECODE 함수를 활용했다.

불규칙한 시간 간격일 경우에도 작업 시각을 기반으로 DECODE를 활용하면 가능할 것 같다. 그러나 하루 수행 횟수가 서너 번 정도라면 그냥 각 시각마다 실행되도록 서너 개의 JOB을 등록시켜주는 것도 생각해볼 수 있다.

원래 문제는 불규칙한 시각+평일 조건을 만족해야 하므로 하나의 interval 수식으로 해결하려면 수식이 무척 복잡해질 것 같다. interval 수식이 복잡해지면 이해가기도 어려워 진고, 나중에 수정하고 싶을 때 문제가 생길 수도 있다.

참고로 10g부터는 DBMS_JOB 대신 DBMS_SCHEDULER을 쓰도록 권고하고 있다.




.주기적으로 수행되어지는 JOB을 JOB QUEUE를 사용하여 스케줄링 할 수 있습니다.. JOB을 스케줄링 하기 위해.주기적으로 수행되어지는 JOB을 JOB QUEUE를 사용하여 스케줄링 할 수 있습니다.. 
 JOB을 스케줄링 하기 위해서 ORACLE의 DBMS_JOB 패키지를 이용합니다.. 
 JOB QUEUE PROCESS가 JOB QUEUE 안의 잡을 수행합니다.. 
 JOB으로 등록될 수 있는 것은 PL/SQL 프로시저 또는 패키지가 되며 
 예를 들어소스 디비의 테이블들에서 타겟 테이블로 데이터를 적재하는 프로시저를 생성했는데 
 1분단위로 데이터를 타겟 테이블로 적재를 해야 할 때 DBMS_JOBS에 등록하여 
 스케줄링 할 수 있습니다. 

.JOB_QUEUE_PROCESSES 파라미터가 이와 관련된 초기화 파라미터로 0으로 설정되면 
 JOB QUEUE PROCESS는 시작되지 않으며 JOB QUEUE의 어느 잡도 수행되지 않습니다.. 
 JOB_QUEUE_PROCESSES 파라미터의 MAX값이 설정되어야 오라클 인스턴스 위에서 
 동시에 잡을 수행할 수 있다. 설정할 수 있는 최고 값은 1000입니다.. 
 JOB_QUEUE_PROCESSES=60 과 같이 설정할 수 있습니다.. 

.등록되거나 수행되는 잡에 대해서는 DBA_JOBS 또는 USER_JOBS 딕셔너리 뷰를 통해 
 확인 할 수 있다. 

.JOB_QUEUE_PROCESSES 는 다이나믹 하게 DB를 SHUTDOWN하지 않고 ALTER SYSTEM 
 명령을 이용해서 설정할 수 있습니다. 
 ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 20; 

.JOB QUEUE안의 JOB을 스케줄링 하기 위해서는 DBMS_JOBS패키지를 사용할 수 있으며 
 JOB_QUEUE를 사용하기 위해 관련된 DB 권한은 없다. 

.다음은 DBMS_JOBS의 패키지를 사용하기 위한 패키지의 프로시져들입니다. 
  
  SUBMIT - 잡큐의 잡을 등록합니다. 
  REMOVE - 잡큐의 잡을 제거합니다. 
  CHANGE - 잡큐의 잡을 변경합니다. 
  NEXT_DATE - 잡의 다음 수행시간을 변경합니다. 
  INTERVAL - 잡 수행 주기를 변경합니다. 
  WHAT - 잡으로 등록된 프로시저 또는 패키지를 변경합니다. 
  RUN - 잡을 수동으로 강제로 수행합니다. 

 .새 JOB을 JOB QUEUE에 등록하기 위해 사용되는 파라미터로 DBMS_JOB.SUBMIT()에 들어가느 
  파라미터 입니다. 
  
  JOB - OUTPUT 파라미터로 생성한 잡에 의해 할당되는 식별자 입니다. 
  WHAT - JOB QUEUE에 등록되는 PL/SQL 프로시저 또는 패키지 입니다. 
  NEXT_DATE - 잡이 수행되는 다음 시간입니다. 
  INTERVAL - 잡이 수행되는 주기로 초 단위까지 지정 가능합니다. 
   
  JOB_QUEUE에 등록하는 예제입니다. 
VARIABLE jobno NUMBER 
BEGIN 
	DBMS_JOB.SUBMIT
	(
		:jobno, 
		'SP_IN_EMP_SAL;', 
		SYSDATE, 
		'SYSDATE + 1'
	); 
COMMIT; 
END; 
/ 
위의 PL/SQL문을 SQL PLUS에서 수행합니다. 
첫번째 파라미터가 JOB NUMBER가 부여되는 부분이고 
두번째 파라미터가 WHAT으로 SP_IN_EMP_SAL이라는 프로시저를 등록했습니다. 
세번째 파라미터가 NEXT_DATE이며 4번째 파라미터가 잡 수행 주기로 하루에 한번씩 
수행하라는 의미입니다. 

DBMS_JOB을 이용하면 특정시간, 특정요일, 특정일, 30초단위, 매분 정각, 매시정각 
등 다양하게  잡을 스케줄링 하는 것이 가능합니다. 
ETL 수행 할 때도 유용하게 사용할 수 있습니다. 
 
잡 수행 간격 조정의 예 
 .SYSDATE+ 7  :  7일에 한번씩 잡이 수행됩니다. 
 .SYSDATE+1/24 : 1시간에 한번씩 잡이 수행됩니다. 
 .SYSDATE+30/86400 : 30초에 한번씩 잡이 수행됩니다. 
 .최초 잡 수행시간이 14:02분일 경우 매시 14:02분에 잡을 수행해야 될 경우 
   =>trunc(SYSDATE,'MI')+1/24  
 .최조 잡 수행시간이 06시 이고 매 8시간마다 정각에 잡이 수행되어야 될 경우 
   =>trunc(SYSDATE,'MI')+8/24 
 .매주 월요일 정각 3시에 잡이 수행되어야 할 경우 
   =>NEXT_DAY(TRUNC(SYSDATE),'MONDAY')+15/25 
 .각 분기마다 첫번째 월요일에 잡이 수행되어야 될 경우 
   =>NEXT_DAY(ADD_MONTHS(TRUNC(SYSDATE,'Q'),3),'MONDAY') 

주의> dbms_job으로 잡을 스케줄링하게 될 경우 예를 들어 잡 최초 수행시간이 22일 14:00시이고 
         매시 정각에 잡이 수행되어야 할 경우 SYSDATE+1/24로 간격을 주게 되면 매 정시에 도는 것이 
         아니라 잡 수행 시간에 따라 약간씩 늦어지게 되어 14:00:04 => 15:00:07 => 16:00:10 이런식으로 
         잡 수행시간이 잡히게 됩니다. 따라서 정각에 수행되게 하려면 trunc함수를 이용해서 무조건 분에서 
         잘라내여 00으로 만들어 준다. trunc(SYSDATE,'MI') 

잡의 삭제
 
BEGIN 
	DBMS_JOB.REMOVE(14443); 
END; 
/  
14443은 잡 번호 이다. USER_JOBS 데이터 딕셔너리 뷰를 보면 잡 번호를 알 수 있습니다. 

잡의 변경 
 
BEGIN 
 DBMS_JOB.CHANGE(14144, NULL, NULL, 'SYSDATE + 3'); 
 END; 
 / 

잡으로 등록된 프로시저/패키지 변경
 
BEGIN 
 DBMS_JOB.WHAT(14144, 
     'SP_IN_EMP_SAL;'); 
END; 
/ 
잡 다음 수행시간 변경
 
BEGIN 
 DBMS_JOB.NEXT_DATE(14144, TRUNC(SYSDATE,'MI') + 4); 
END; 
/ 
잡 수행 간격 변경
 
BEGIN 
 DBMS_JOB.INTERVAL(14144, TRUNC(SYSDATE,'MI')+30/1440); 
END; 
/ 
잡 수행 정지 잡이 BROKEN되면 잡은 수행되지 않으며 강제로 수행 할 시에는 DBMS_JOB.RUN()을 통해 수행합니다..
 
BEGIN 
 DBMS_JOB.BROKEN(14144, TRUE); 
END; 
/
잡큐 정보 VIEWING DBA_JOBS, USER_JOBS, ALL_JOBS를 이용합니다.
 
SELECT JOB, NEXT_DATE, NEXT_SEC, FAILURES, BROKEN 
FROM DBA_JOBS; 

JOB    NEXT_DATE  NEXT_SEC  FAILURES   B 
------- ---------  --------   --------   - 
9125    01-JUN-01   00:00:00     4       N 
14144   24-OCT-01   16:35:35    0       N 
9127    01-JUN-01   00:00:00    16       Y 
3 rows selected. 
DBMS_JOB의 활용예제를 주기적으로 소스테이블에서 타켓 테이블로 적재할 시 어떻게 사용할 수 있는지 간단하게 예를 만들었습니다
   
--수행될 잡의 목록이 들어갈 테이블 
CREATE TABLE JOB_LIST 
(
	JOB_ID VARCHAR2(2), 
	JOB_TYPE VARCHAR2(1), 
	JOB_NAME VARCHAR2(30), 
	JOB_EXEC_HOUR VARCHAR(2), 
	JOB_PARENTID VARCHAR2(2), 
	CONSTRAINTS JOB_LIST_PK PRIMARY KEY(JOB_ID) 
	USING INDEX 
	TABLESPACE CYS_INDEX PCTFREE 0 STORAGE(INITIAL 32K NEXT 32K PCTINCREASE 0) 	NOLOGGING) 
	TABLESPACE CYS_DATA PCTFREE 0 STORAGE(INITIAL 128K NEXT 128K PCTINCREASE 0
); 
/   

CREATE UNIQUE INDEX JOB_LIST_IDX01 ON JOB_LIST(JOB_NAME,JOB_EXEC_HOUR) 
TABLESPACE CYS_INDEX PCTFREE 0 STORAGE(INITIAL 64K NEXT 64K PCTINCREASE 0); 
/ 

-잡 수행 히스토리 테이블로 하루에 한번씩 JOB_LIST 테이블에서 LOG테이블로 JOB_LIST가 복사된다. 
CREATE TABLE JOB_LOG 
(
	JOB_ID VARCHAR2(2), 
	JOB_EXEC_DATE VARCHAR2(8), 
	JOB_START_TIME DATE, 
	JOB_END_TIME DATE, 
	JOB_DATASTART_TIME DATE, 
	JOB_DATAEND_TIME DATE, 
	JOB_STATUS VARCHAR2(1), 
	JOB_ERR_MSG VARCHAR2(100), 
	CONSTRAINTS JOB_LOG_PK PRIMARY KEY(JOB_ID,JOB_EXEC_DATE) USING INDEX
	TABLESPACE CYS_INDEX PCTFREE 0 STORAGE(INITIAL 128K NEXT 128K PCTINCREASE 0) NOLOGGING, 
	CONSTRAINTS JOB_LIST_FK FOREIGN KEY(JOB_ID) REFERENCES JOB_LIST(JOB_ID)) 
	TABLESPACE CYS_DATA STORAGE(INITIAL 1M NEXT 1M PCTINCREASE 0) 

 --JOB_ID를 부여하기 위한 시퀀스 
CREATE SEQUENCE JOB_NUM START WITH 1 INCREMENT BY 1 ;

--하루에 한번 DBMS_JOB을 이용하여 JOB_LIST의 JOB들을 JOB_LOG에 INSERT하기 위한 프로시져 
--다음날 수행할 JOB을 LOG로 넣는다. 
CREATE OR REPLACE PROCEDURE SP_IN_JOB_LOG(V_INDATE IN VARCHAR2 DEFAULT NULL) 
AS 
BEGIN 
	INSERT INTO JOB_LOG SELECT JOB_ID, 
		NVL(V_INDATE,TO_CHAR(SYSDATE+1,'YYYYMMDD')), 
		NULL, 
		NULL, 
		NULL, 
		NULL, 
		'N', 
		NULL 
		FROM JOB_LIST; 
	
	COMMIT; 
END SP_IN_JOB_LOG; 

--SP_IN_JOB_LOG 프로시저를 DBMS_JOB에 등록한다. 
DECLARE 
    JOB_NUMBER NUMBER; 
BEGIN 
  DBMS_JOB.SUBMIT(JOB_NUMBER,  --JOB번호 
        'SP_IN_JOB_LOG;',  --프로시저명 
         TO_DATE('20050208180000','YYYYMMDDHH24MISS'),  --NEXT_DATE 
        'TRUNC(SYSDATE,''MI'')+1');  --잡 수행 간격(매일 정각 6시) 
END; 

--JOB_LIST에 수행할 프로시져(JOB)을 등록 
--DBA_USERS테이블을 이용해서 24개의 로우를 만들어 낸 후 카테시안 프러덕을 이용 
INSERT INTO JOB_LIST 
SELECT JOB_NUM.NEXTVAL JOB_ID, 
    JOB_TYPE, 
    JOB_NAME, 
    B.CNT JOB_EXEC_HOUR, 
    NULL 
FROM( 
  SELECT NULL JOB_ID, 
      'F' JOB_TYPE, 
      'SP_IN_F_SALE_SUM' JOB_NAME, 
      NULL JOB_EXEC_HOUR, 
      NULL 
  FROM DUAL) A, 
 ( SELECT LPAD(ROWNUM-1,2,'0') CNT FROM DBA_TABLES 
     WHERE ROWNUM<25) B 

COMMIT; 

--JOB_LIST를 JOB_LOG로 INSERT(현재 SP_IN_JOB_LOG 가 다음일을 INSERT하도록 되어 있으므로 해당일을 넣어줌) 
EXEC SP_IN_JOB_LOG('20050208'); 

 --제대로 들어갔는지 확인 
SELECT * FROM JOB_LOG; 

 --SOURCE 테이블을 시간단위로 섬머리 해서 TARGET 테이블로 적재하기 위한 프로시져 
--ERROR없이 매 시간 돌 때는 파라미터 없이 SP_IN_F_SALE_SUM으로 수행 되고 수동으로 어떤 데이터의 
--범위를 적재해야 할 경우 시간의 범위를 파라미터로 넘겨줌 
CREATE OR REPLACE PROCEDURE SP_IN_F_SALE_SUM(V_STARTTIME IN VARCHAR2 DEFAULT NULL, V_ENDTIME IN VARCHAR2 DEFAULT NULL) 
AS 
  D_STARTTIME DATE; 
  D_ENDTIME DATE; 
  V_ERR_MSG VARCHAR2(100); 
BEGIN 
  
 --프로시저가 파라미터 값이 없이 수행될 경우 
 IF V_STARTTIME IS NULL AND V_ENDTIME IS NULL THEN 
  SELECT NVL(JOB_DATAEND_TIME,TRUNC(SYSDATE-1/24,'HH24')) 
  INTO D_STARTTIME 
  FROM JOB_LOG 
  WHERE JOB_ID=(SELECT JOB_ID FROM JOB_LIST 
             WHERE JOB_NAME='SP_IN_F_SALE_SUM' 
       AND JOB_EXEC_HOUR=TO_CHAR(SYSDATE-1/24,'HH24')) 
  AND JOB_EXEC_DATE=TO_CHAR(SYSDATE,'YYYYMMDD') 
  AND JOB_STATUS='Y'; 

  D_ENDTIME:=TRUNC(SYSDATE,'HH24'); 
 ELSE 
  SELECT NVL(JOB_DATAEND_TIME,TO_DATE(V_STARTTIME,'YYYYMMDDHH24MISS')) 
  INTO D_STARTTIME 
  FROM JOB_LOG 
  WHERE JOB_ID=(SELECT JOB_ID FROM JOB_LIST 
             WHERE JOB_NAME='SP_IN_F_SALE_SUM' 
       AND JOB_EXEC_HOUR=SUBSTR(V_STARTTIME,9,2)) 
  AND JOB_EXEC_DATE=SUBSTR(V_ENDTIME,1,8) 
  AND JOB_STATUS='Y'; 

  D_ENDTIME:=TO_DATE(V_ENDTIME,'YYYYMMDDHH24MISS'); 
 END IF; 
    
 --수행되는 프로시저의 START시간을 찍어주고 RUNNING으로 표시 
 UPDATE JOB_LOG 
 SET JOB_START_TIME=SYSDATE, 
  JOB_STATUS='R' 
 WHERE JOB_ID=(SELECT JOB_ID FROM JOB_LIST 
         WHERE JOB_NAME='SP_IN_F_SALE_SUM' 
      AND JOB_EXEC_HOUR=SUBSTR(V_STARTTIME,9,2)) 
 AND JOB_EXEC_DATE=SUBSTR(V_ENDTIME,1,8); 
  
 -- DML------ 
  
  --수행되어질 INSERT문 
  
 -- DML----- 
  
 COMMIT; 
  
 --프로시저가 ERROR없이 수행이 끝나면 END 시간과 가져온 데이터의 범위를 찍어줌 
 UPDATE JOB_LOG 
 SET JOB_END_TIME=SYSDATE, 
  JOB_DATASTART_TIME=D_STARTTIME, 
  JOB_DATAEND_TIME=D_ENDTIME, 
  JOB_STATUS='Y' 
 WHERE JOB_ID=(SELECT JOB_ID FROM JOB_LIST 
         WHERE JOB_NAME='SP_IN_F_SALE_SUM' 
      AND JOB_EXEC_HOUR=TO_CHAR(D_ENDTIME,'HH24')) 
 AND JOB_EXEC_DATE=SUBSTR(V_ENDTIME,1,8); 
  
 COMMIT; 
  
EXCEPTION 
   WHEN OTHERS THEN 
      V_ERR_MSG:= SUBSTRB(SQLERRM, 1, 80); 
     
     UPDATE JOB_LOG 
     SET JOB_END_TIME=SYSDATE, 
      JOB_STATUS='E', 
      JOB_ERR_MSG=V_ERR_MSG 
           WHERE JOB_ID=(SELECT JOB_ID FROM JOB_LIST 
                  WHERE JOB_NAME='SP_IN_F_SALE_SUM' 
         AND JOB_EXEC_HOUR=TO_CHAR(D_ENDTIME,'HH24')) 
           AND JOB_EXEC_DATE=SUBSTR(V_ENDTIME,1,8); 
     
     COMMIT; 
END SP_IN_F_SALE_SUM; 
/ 

 --SP_IN_F_SALE_SUM 프로시저를 DBMS_JOB에 등록합니다. 
DECLARE 
    JOB_NUMBER NUMBER; 
BEGIN 
  DBMS_JOB.SUBMIT(JOB_NUMBER,  --JOB번호 
        'SP_IN_F_SALE_SUM;',  --프로시저명 
         TO_DATE('20050209000000','YYYYMMDDHH24MISS'),  --NEXT_DATE 
        'TRUNC(SYSDATE,''MI'')+1/24');  --잡 수행 간격(매시간 정각) 
END; 
JOB의 시간이나 간격 등록된 프로시저등을 변경하고자 할 때 DBMS_JOB의 다른 프로시져를 이용해서 변경합니다. 2번째 정리 부분에 설명되어 있습니다.
블로그 이미지

유효하지않음

,
네이버는 POST방식도 허용 하던데 구글은 POST로 넘기면 오류메세지에 관련된 XML만 넘어오더군요
그래서 그냥 GET방식으로 처리하니 정상적인 XML값이 넘어오네요..ㅋㅋ
Java로 작업하고 나서 테스트 해볼려고 함 만들었네요..~~
vKey는 구글에서 생성하고 적용하십시요

==> 본인의 글 입니다. 이 글을 다른곳에 게재하는 경우 본문의 출처를 밝혀주시기 바람니다.
/**
  * 구글맵 키 생성 URL
  * http://code.google.com/intl/ko-KR/apis/maps/signup.html
  *
 **/

DECLARE
	vRequest		UTL_HTTP.req;
	vResponse		UTL_HTTP.resp;
	vResponseText	VARCHAR2(4000);
	vErrorText		VARCHAR2(4000);
	vTxt			VARCHAR2(10);
	vAddress		VARCHAR2(1000);
	vCoordinateX	VARCHAR2(100);
	vCoordinateY	VARCHAR2(100);
	vCoordinates	VARCHAR2(100);
	vXml			XMLType;
	i				BINARY_INTEGER	:= 0;
	
	--구글관련 설정내용
	vUrl			VARCHAR2(200) := 'http://maps.google.com/maps/geo';
	vKey			VARCHAR2(300) := 'ABQIAAAApvInj0M12LgrKqPVykdiShTRzhAzSQ3u4E7LYXha2CwyHvWJ_RTAzTyv3xCX_ja0mBuaI1HJQ9QLgQ';
	vQuery			VARCHAR2(200) := '서울구로구구로동222-12';
	vXmlns			VARCHAR2(100) := 'xmlns="http://earth.google.com/kml/2.0';

	--SPLIT 함수호출
	CURSOR STR_SPLIT(str IN VARCHAR2, sp IN VARCHAR2)
	IS
		SELECT COLUMN_VALUE FROM TABLE(SPLIT(str, sp));
		TYPE TABLE_SPLIT IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
	
	aCoordinates	TABLE_SPLIT;

BEGIN

	--vQuery    := convert(vQuery, 'KO16MSWIN949', 'UTF8');
	vUrl      := vUrl || '?q=' || vQuery || CHR(38) || 'gl=KR' || CHR(38) || 'output=xml' || CHR(38) || 'key=' || vKey;

	DBMS_OUTPUT.put_line('===================================================================');
	DBMS_OUTPUT.put_line('                         전송한 URL                                ');
	DBMS_OUTPUT.put_line('===================================================================');
	DBMS_OUTPUT.put_line(vUrl);
	
	vRequest := UTL_HTTP.begin_request(vUrl,  'GET', 'HTTP/1.1');
	UTL_HTTP.set_header(vRequest, 'Accept-Language',  'ko');
	UTL_HTTP.set_header(vRequest, 'Accept',           'text/xml');
	UTL_HTTP.set_header(vRequest, 'User-Agent',       'Mozilla/4.0');
	UTL_HTTP.set_body_charset('utf8');

	vResponse := UTL_HTTP.get_response(vRequest);

	IF vResponse.status_code = '200'
	THEN
		UTL_HTTP.read_text(vResponse, vResponseText);

		IF vResponseText NOT LIKE 'Result=OK%'
		THEN
			vXml     := XMLType.createXML(TRIM(vResponseText));
			vAddress := NULL;
			i        := 0;

			SELECT vXml.extract('//Response/Placemark/address/text()',           vXmlns).getstringval() INTO vAddress     FROM dual;
			SELECT vXml.extract('//Response/Placemark/Point/coordinates/text()', vXmlns).getstringval() INTO vCoordinates FROM dual;

			IF vAddress IS NOT NULL
			THEN
				FOR COLNAME_LIST IN STR_SPLIT(vCoordinates, ',')
				LOOP
					i := i + 1;
					aCoordinates(i) := COLNAME_LIST.COLUMN_VALUE;
				END LOOP;
				
				IF i > 1 THEN
					vCoordinateX := aCoordinates(1);
					vCoordinateY := aCoordinates(2);
					DBMS_OUTPUT.put_line(CHR(13) || CHR(13));
					DBMS_OUTPUT.put_line('===================================================================');
					DBMS_OUTPUT.put_line('                         주소/좌표 추출                            ');
					DBMS_OUTPUT.put_line('===================================================================');
					DBMS_OUTPUT.put_line('주소   >> ' || vAddress);
					DBMS_OUTPUT.put_line('X 좌표 >> ' || vCoordinateX);
					DBMS_OUTPUT.put_line('Y 좌표 >> ' || vCoordinateY);
				END IF;

			END IF; -- IF vAddress IS NOT NULL End.

			vErrorText := vResponseText;

		END IF; -- IF vResponseText NOT LIKE 'Result=OK%' End.

	ELSE
		vErrorText := 'HTTP status: '||vResponse.status_code||'-'||vResponse.reason_phrase;
	END IF; -- IF vResponse.status_code = '200' End.

	DBMS_OUTPUT.put_line(CHR(13) || CHR(13));
	DBMS_OUTPUT.put_line('===================================================================');
	DBMS_OUTPUT.put_line('                         전송받은 XML                              ');
	DBMS_OUTPUT.put_line('===================================================================');
	DBMS_OUTPUT.put_line(vErrorText);


	UTL_HTTP.end_response(vResponse);
END;
블로그 이미지

유효하지않음

,

iSCSI on Solaris 10 x86

OS/Solaris 2009. 2. 19. 13:10

[출처] http://blog.scottlowe.org/2006/12/05/iscsi-on-solaris-10-x86/

Given that I’m neither a Solaris expert (yet) nor an iSCSI expert (yet), I knew that it would be a bit of a challenge to make this work.  Fortunately, a found avery useful blog posting by Frank Berger that gave me the framework I needed to get started.  From there, Sun’s documentation provided the rest of the necessary details.  Perhaps this documentation will prove moderately useful as well.

First, I added the following lines to the /etc/ietd.conf on the CentOS iSCSI target server:

Target iqn.2006-08.net.example:server.lun1
        IncomingUser username complicatedpassword
        Lun 1 Path=/dev/vg00/isanvol1,Type=fileio
        Alias iet-lun1
        MaxConnections          8
        InitialR2T              No
        ImmediateData           Yes

A quick restart of the iSCSI target service and I was all set on the target side.  If you were going to do this yourself in your own environment, you’d need to modify the “IncomingUser” and “Lun X Path”.  In this instance I’m using LVM on CentOS, so my path specifies a logical volume in a volume group.  Your configuration will differ, obviously.  Alternately, if you are using a different iSCSI target implementation, you’d need to configure it appropriately.  (I hope to be able to do some testing against a NetApp iSCSI target in the near future.)

On the initiator side, everything is done with the “iscsiadm” command.  This command is fairly self-explanatory and has built-in help (-?) throughout most of the options, but it did take me a little bit of time to get things working.

First, we have to make sure that the iSCSI initiator is online:

svcs -a | grep iscsi

If disabled, then we can enable it with this command:

svcadm enable svc:/network/iscsi_initiator

From there, we configure the iSCSI initiator:

iscsiadm add discovery-address 10.1.1.1:3260
iscsiadm modify initiator-node -a CHAP
iscsiadm modify initiator-node -H username
iscsiadm modify initiator-node -C
(specify CHAP password)
iscsiadm modify discovery --sendtargets enable

Because I’d also specified a static config as well (dynamic discovery didn’t seem to be working as I expected; more on that in a moment), using “iscsiadm list target” now returned two iSCSI targets.  They appeared to be different targets, and since I do have two targets defined on the iSCSI server (one for VMware and one for this), I didn’t want to take any chances on affecting the VMware LUN.  So, I removed and disabled the dynamic discovery, removed the static config, and then re-added the static config:

iscsiadm add static-config iqn.2006-08.net.example:server.lun1,
10.1.1.1:3260

(This should all be on one line; it was wrapped here for readability.)  After doing that, “iscsiadm list target” showed only a single target identified as “server.lun1”, which assured me that I wasn’t seeing the VMware LUN.

<aside>In a more complex environment, how does one ensure that iSCSI LUNs are properly isolated from unwanted hosts?  The “IncomingUser” parameter was different between my VMware LUN and the raw LUN being presented to Solaris, so in theory I would have been safe.  Better safe than sorry, in my opinion.</aside>

After I was sure that the iSCSI initiator was properly seeing the LUN, then I created a new device, created a new filesystem on that device, and then mounted it:

devfsadm -c iscsi
format (selected new disk identified as iSCSI)
newfs /dev/dsk/c2t1d0s2
mount /dev/dsk/c2t1d0s2 /export/iscsi

Of course, you’ll need to modify the above commands slightly depending upon your configuration, but the overall process should be pretty close to what I’ve outlined above.




Step 1: configuring the iSCSI initiator on both V215 nodes:


root@solcluster03:~> svcadm enable iscsi_initiator
root@solcluster03:~> iscsiadm list initiator-node
Initiator node name: iqn.1986-03.com.sun:01:00144f7109f2.48aa5d81
Initiator node alias: -
Login Parameters (Default/Configured):
Header Digest: NONE/-
Data Digest: NONE/-
Authentication Type: NONE
RADIUS Server: NONE
RADIUS access: unknown
Configured Sessions: 1
root@solcluster03:~> iscsiadm add discovery-address 172.19.107.9
root@solcluster03:~> devfsadm -c iscsi
root@solcluster03:~> iscsiadm modify discovery -t enable
root@solcluster03:~> format
Searching for disks...done


AVAILABLE DISK SELECTIONS:
0. c1t0d0 
/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@0,0
1. c1t1d0 
/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@1,0
2. c2t010000144F20E16400002A0048AEB3ABd0 
/scsi_vhci/ssd@g010000144f20e16400002a0048aeb3ab
3. c2t010000144F20E16400002A0048609421d0 
/scsi_vhci/ssd@g010000144f20e16400002a0048609421
Specify disk (enter its number): ^D
root@solcluster03:~>

---------------------------------------------------------------

Step 2: ZFS creation (some uninteresting stuff in there, but I don't 
want to cut something out):


root@solcluster03:~> NOINUSE_CHECK=1 zpool create iscsi 
c2t010000144F20E16400002A0048609421d0
root@solcluster03:~> zfs set mountpoint=/export/iscsi iscsi

root@solcluster03:~> zfs list
NAME USED AVAIL REFER MOUNTPOINT
iscsi 92K 9,78G 24,5K /export/iscsi
root@solcluster03:~>

root@solcluster03:~> zfs set compression=on iscsi
root@solcluster03:~> zfs set backup:zfs:avoidscrub=true iscsi
root@solcluster03:~> zfs set storage:cluster:hasp=true iscsi
root@solcluster03:~> zfs set storage:cluster:avs=false iscsi
root@solcluster03:~> zfs get all iscsi
NAME EIGENSCHAFT WERT QUELLE
iscsi type filesystem -
iscsi creation Mi Sep 3 9:14 2008 -
iscsi used 92K -
iscsi available 9,78G -
iscsi referenced 24,5K -
iscsi compressratio 1.00x -
iscsi mounted yes -
iscsi quota none default
iscsi reservation none default
iscsi recordsize 128K default
iscsi mountpoint /export/iscsi local
iscsi sharenfs off default
iscsi checksum on default
iscsi compression off default
iscsi atime on default
iscsi devices on default
iscsi exec on default
iscsi setuid on default
iscsi readonly off default
iscsi zoned off default
iscsi snapdir hidden default
iscsi aclmode groupmask default
iscsi aclinherit secure default
iscsi canmount on default
iscsi shareiscsi off default
iscsi xattr on default
iscsi storage:cluster:hasp true local
iscsi backup:zfs:avoidscrub true local
iscsi storage:cluster:avs false local
root@solcluster03:~>
root@solcluster03:~> zfs create iscsi/data
root@solcluster03:~> zfs list | grep iscsi
iscsi 158K 9,78G 26,5K /export/iscsi
iscsi/data 24,5K 9,78G 24,5K /export/iscsi/data
root@solcluster03:~>

---------------------------------------------------------------

Step 3: Creating the HA-NFS resource group (called "hanfs-rg")

root@solcluster03:~> clresourcegroup create -p Pathprefix=/export/iscsi 
hanfs-rg
root@solcluster03:~> clresourcegroup status

Cluster Resource Groups ===

Group Name Node Name Suspended Status
---------- --------- --------- ------
hanfs-rg solcluster04 No Unmanaged
solcluster03 No Unmanaged

root@solcluster03:~>

---------------------------------------------------------------

Step 4: Creating a logical hostname resource (would be needed for HA-NFS 
later)

root@solcluster03:~> host solcluster
solcluster.dlan.cinetic.de has address 172.20.5.125
root@solcluster03:~>

root@solcluster03:~> grep solcluster.dlan.cinetic.de /etc/hosts
172.20.5.125 solcluster solcluster.dlan.cinetic.de
root@solcluster03:~>

root@solcluster03:~> clreslogicalhostname create -g hanfs-rg -h 
solcluster hanfs-ip
root@solcluster03:~> clreslogicalhostname status

Cluster Resources ===

Resource Name Node Name State Status Message
------------- --------- ----- --------------
hanfs-ip solcluster04 Offline Offline
solcluster03 Offline Offline

root@solcluster03:~>

---------------------------------------------------------------

Step 5: Creating the HAStoragePlus resource


root@solcluster03:~> clresourcetype register SUNW.HAStoragePlus
root@solcluster03:~>

root@solcluster03:~> clresource create -t SUNW.HAStoragePlus -g hanfs-rg 
-p Zpools=iscsi hanfs-hasp
root@solcluster03:~> clresource list
hanfs-ip
hanfs-hasp
root@solcluster03:~>
---------------------------------------------------------------

Note: The zpool is being exported by the clresource command. Takes some 
time.


Step 6: Taking the resource group online

root@solcluster03:~> clresourcegroup list
hanfs-rg
root@solcluster03:~>


root@solcluster03:~> clresourcegroup online -M hanfs-rg

---------------------------------------------------------------


And that's it. The command never returns. the zpool is never imported, 
the resource themselves stay "Offline". After a reboot, the hasp 
resource is "Pending" and further modification of the configuration is 
impossible. No log entries btw, seems like

Solaris 10 Update 5, Solaris Cluster 3.2 Update 1, actual recommended 
patches cluster applied, using 2x V215 as iSCSI initiatiors and 1x X4500 
as the iSCSI target.

블로그 이미지

유효하지않음

,

[출처] http://www.cyberciti.biz/tips/howto-setup-linux-iscsi-target-sanwith-tgt.html

Linux target framework (tgt) aims to simplify various SCSI target driver (iSCSI, Fibre Channel, SRP, etc) creation and maintenance. The key goals are the clean integration into the scsi-mid layer and implementing a great portion of tgt in user space.

The developer of IET is also helping to develop Linux SCSI target framework (stgt) which looks like it might lead to an iSCSI target implementation with an upstream kernel component. iSCSI Target can be useful:

a] To setup stateless server / client (used in diskless setups).
b] Share disks and tape drives with remote client over LAN, Wan or the Internet.
c] Setup SAN - Storage array.
d] To setup loadbalanced webcluser using cluster aware Linux file system etc.

In this tutorial you will learn how to have a fully functional Linux iSCSI SAN using tgt framework.

iSCSI target (server)

Storage resource located on an iSCSI server known as a "target". An iSCSI target usually represents nothing but hard disk storage. As with initiators, software to provide an iSCSI target is available for most mainstream operating systems.

iSCSI initiator (client)

An initiator functions as an iSCSI client. An initiator typically serves the same purpose to a computer as a SCSI bus adapter would, except that instead of physically cabling SCSI devices (like hard drives and tape changers), an iSCSI initiator sends SCSI commands over an IP network.

Debian / Ubuntu Linux Install tgt

Type the following command to install Linux target framework user-space tools:
$ sudo apt-get install tgt

CentOS / RHEL / Red Hat Linux Install tgt

RHEL 5.2 and older version do not have tgt tools. However, RHEL 5.3 (preview version) comes with tgt tools.

tgtadm - Linux SCSI Target Administration Utility

tgtadm is used to monitor and modify everything about Linux SCSI target software: targets, volumes, etc. This tool allows a system to serve block-level SCSI storage to other systems that have a SCSI initiator. This capability is being initially deployed as a Linux iSCSI target, serving storage over a network to any iSCSI initiator.

Start tgtd

To start the tgtd, enter:
# /usr/sbin/tgtd
Under RHEL 5.3 to start the tgtd service, enter:
# /etc/init.d/tgtd start

Define an iscsi target name

The following example creates a target with id 1 (the iqn is 19 iqn.2001-04.com.example:storage.disk2.amiens.sys1.xyz) and adds a 20 logical unit (backed by /dev/hdc1) with lun 1.
# tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.2001-04.com.example:storage.disk2.amiens.sys1.xyz

To view the current configuration, enter:
# tgtadm --lld iscsi --op show --mode target
Sample output:

Target 1: iqn.2001-04.com.example:storage.disk1.amiens.sys1.xyz
    System information:
        Driver: iscsi
        Status: running
    I_T nexus information:
    LUN information:
        LUN: 0
            Type: controller
            SCSI ID: deadbeaf1:0
            SCSI SN: beaf10
            Size: 0
            Online: No
            Poweron/Reset: Yes
            Removable media: No
            Backing store: No backing store
    Account information:
    ACL information:

Add a logical unit to the target (/dev/sdb1):
# tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 -b /dev/sdb1

A note about home computer / test system

Most production boxes will only use iSCSI root with real iSCSI devices, but for testing purposes it can be quite useful to set up an iSCSI target on your image server. This is useful for testing and learning iSCSI target and iSCSI initiator at home, simply use filesystem for testing purpose. Usedd command to create diskbased filesystem:
# dd if=/dev/zero of=/fs.iscsi.disk bs=1M count=512
Add /fs.iscsi.disk as a logical unit to the target:
# tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 -b /fs.iscsi.disk
Now, you should able to view details:
# tgtadm --lld iscsi --op show --mode target
Sample output:

Target 1: iqn.2001-04.com.example:storage.disk1.amiens.sys1.xyz
    System information:
        Driver: iscsi
        Status: running
    I_T nexus information:
    LUN information:
        LUN: 0
            Type: controller
            SCSI ID: deadbeaf1:0
            SCSI SN: beaf10
            Size: 0
            Online: No
            Poweron/Reset: Yes
            Removable media: No
            Backing store: No backing store
        LUN: 1
            Type: disk
            SCSI ID: deadbeaf1:1
            SCSI SN: beaf11
            Size: 512M
            Online: Yes
            Poweron/Reset: Yes
            Removable media: No
            Backing store: /fs.iscsi.disk
    Account information:
    ACL information:

Accept iSCSI Target

To enable the target to accept any initiators, enter:
# tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
This should open network port # 3260:
# netstat -tulpn | grep 3260
Sample output:

tcp        0      0 0.0.0.0:3260            0.0.0.0:*               LISTEN      27328/tgtd
tcp6       0      0 :::3260                 :::*                    LISTEN      27328/tgtd      

And you are done. Your system is configured as iSCSI Target. Remote client computer can access this computers hard disk over network. Your can use cluster aware filesystem to setup real shared storage for small business. Open TCP port 3260 in your firewall, if required.

How do I access iSCSI Target (server) via iSCSI initiator (client)?

See detailed os specific iSCSI initiator instuctions:

  1. RHEL 4 or RHEL 5 Linux iSCSI initiator tutorial.
  2. Debian Linux iSCSI initiator tutorial.
  3. FreeBSD iSCSI initiator tutorial.
  4. Windows iSCSI initiator tutorial.

Following is a quick way to access iSCSI target, under RHEL 5. Let us say your server iSCSI Target IP is 192.168.1.2. Type the following command to discover targets at a given IP address such as 192.168.1.2 (use 127.0.0.1 if you are testing it from same computer):
# iscsiadm --mode discovery --type sendtargets --portal 192.168.1.2
OR
# iscsiadm --mode discovery --type sendtargets --portal 127.0.0.1
Sample output:

127.0.0.1:3260,1 iqn.2001-04.com.example:storage.disk1.amiens.sys1.xyz

Login to the iscsi target session:
# iscsiadm --mode node --targetname iqn.2001-04.com.example:storage.disk1.amiens.sys1.xyz --portal 192.168.1.2:3260 --login
OR
# iscsiadm --mode node --targetname iqn.2001-04.com.example:storage.disk1.amiens.sys1.xyz --portal 127.0.0.1:3260 --login
Verify that login was successful:
# tail -f /var/log/messages
Sample output:

Nov 11 07:34:04 vivek-desktop kernel: [ 9039.562312] scsi 6:0:0:1: Direct-Access     IET      VIRTUAL-DISK     0001 PQ: 0 ANSI: 5
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.572268] sd 6:0:0:1: [sdc] 1048576 512-byte hardware sectors (537 MB)
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.572374] sd 6:0:0:1: [sdc] Write Protect is off
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.572530] sd 6:0:0:1: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.572715] sd 6:0:0:1: [sdc] 1048576 512-byte hardware sectors (537 MB)
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.572790] sd 6:0:0:1: [sdc] Write Protect is off
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.572940] sd 6:0:0:1: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.572946]  sdc: unknown partition table
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.573492] sd 6:0:0:1: [sdc] Attached SCSI disk
Nov 11 07:34:04 vivek-desktop kernel: [ 9039.573593] sd 6:0:0:1: Attached scsi generic sg4 type 0

sdc is new scsi disk. You may need to restart iSCSI to probe partition and check disks:
# service iscsi restart
# partprobe
# fdisk -l

You can now create parition and mount file system using usual fdisk and mkfs.ext3 commands:
# fdisk /dev/sdc
# mkfs.ext3 /dev/sdc1mkdir /iscsi
# mkdir /iscsi
# mount /dev/sdc1 /iscsi
# df -H

Sample output:

Filesystem             Size   Used  Avail Use% Mounted on
/dev/sda2               99G    30G    64G  32% /
tmpfs                  1.1G      0   1.1G   0% /lib/init/rw
varrun                 1.1G   361k   1.1G   1% /var/run
varlock                1.1G      0   1.1G   0% /var/lock
udev                   1.1G   2.9M   1.1G   1% /dev
tmpfs                  1.1G   312k   1.1G   1% /dev/shm
/dev/sda1              105G    32G    73G  31% /media/sda1
/dev/sda5              294G   275G    20G  94% /share
/dev/sdb2              247G   119G   116G  51% /disk1p2
/dev/sdc1              520M    11M   483M   3% /iscsi
블로그 이미지

유효하지않음

,

[출처] http://www.cyberciti.biz/tips/howto-centos-rhel4-iscsi-initiators.html

I've received a couple of email about setting up iSCSI under CentOS 4 or RHEL ES 4 server. Previously, I wrote about iSCSI under CentOS 5 / RHEL 5 server.

Requirements

[a] Following instructions tested on RHEL ES 4 and CentOS 4 only. (See RHEL 5/ CentOS 5 / Debian/ Ubuntu Linux specific instructions here).
[b] You need following information
[c] ISCSI Username
[d] ISCSI Password
[e] ISCSI Server IP / hostname

CentOS Linux v4.x - Install iscsi-initiator-utils

Type the following command:
# yum install iscsi-initiator-utils

Redhat ES Linux v4.x - Install iscsi-initiator-utils

Type the following command:
# up2date iscsi-initiator-utils

Configure iSCSI

Open /etc/iscsi.conf file, enter:
# vi /etc/iscsi.conf
Setup it as follows:

DiscoveryAddress=ISCSI_TARGET_HOST_OR_IP
 OutgoingUserName=ISCSI_USER_NAME
 OutgoingPassword=ISCSI_PASSWORD
 LoginTimeout=15

Save and close the file.

Start the iscsi service

Type the following command to start iscsi service so that you can see block device:
# chkconfig iscsi on
# /etc/init.d/iscsi start

Run any one of the following to find out new block device name:
# fdisk -l
# tail -f /var/log/messages
# find /sys/devices/platform/host* -name "block*"

Format iSCSI device

Use fdisk and mkfs.ext3 commands. First, create a partition (assuming that /dev/sdc is a new block device assigned to iscsi) :
# fdisk /dev/sdc
# mkfs.ext3 /dev/sdc1

Create /mnt/iscsi directory:
# mkdir -p /mnt/iscsi
Open /etc/fstab file and append config directive:
/dev/sdc1 /mnt/iscsi ext3 _netdev 0 0
Save and close the file. Mount the parition /dev/sdc1:
# mount -a
# df -H

블로그 이미지

유효하지않음

,

[출처] http://www.cyberciti.biz/tips/rhel-centos-fedora-linux-iscsi-howto.html

Internet SCSI (iSCSI) is a network protocol s that allows you to use of the SCSI protocol over TCP/IP networks. It is good alternative to Fibre Channel-based SANs. You can easily manage, mount and format iSCSI Volume under Linux. It allows access to SAN storage over Ethernet.

Open-iSCSI Project

Open-iSCSI project is a high-performance, transport independent, multi-platform implementation of iSCSI. Open-iSCSI is partitioned into user and kernel parts.

Instructions are tested on:
[a] RHEL 5
[b] CentOS 5
[c] Fedora 7
[d] Debian / Ubuntu Linux

Install Required Package

iscsi-initiator-utils RPM package - The iscsi package provides the server daemon for the iSCSI protocol, as well as the utility programs used to manage it. iSCSI is a protocol for distributed disk access using SCSI commands sent over Internet Protocol networks. This package is available under Redhat Enterprise Linux / CentOS / Fedora Linux and can be installed using yum command:
# yum install iscsi-initiator-utils

A note about Debian / Ubuntu Linux

If you are using Debian / Ubuntu Linux install open-iscsi package, enter:
$ sudo apt-get install open-iscsi

iSCSI Configuration

There are three steps needed to set up a system to use iSCSI storage:

  1. iSCSI startup using the init script or manual startup. You need to edit and configure iSCSI via /etc/iscsi/iscsid.conf file
  2. Discover targets.
  3. Automate target logins for future system reboots.
  4. You also need to obtain iSCSI username, password and storage server IP address (target host)

Step # 1: Configure iSCSI

Open /etc/iscsi/iscsid.conf with vi text editor:
# vi /etc/iscsi/iscsid.conf
Setup username and password:
node.session.auth.username = My_ISCSI_USR_NAME
node.session.auth.password = MyPassword
discovery.sendtargets.auth.username = My_ISCSI_USR_NAME
discovery.sendtargets.auth.password = MyPassword

Where,

  • node.session.* is used to set a CHAP username and password for initiator authentication by the target(s).
  • discovery.sendtargets.* is used to set a discovery session CHAP username and password for the initiator authentication by the target(s)

You may also need to tweak and set other options. Refer to man page for more information. Now start the iscsi service:
# /etc/init.d/iscsi start

Step # 2: Discover targets

Now use iscsiadm command, which is a command-line tool allowing discovery and login to iSCSI targets, as well as access and management of the open-iscsi database. If your storage server IP address is 192.168.1.5, enter:
# iscsiadm -m discovery -t sendtargets -p 192.168.1.5
# /etc/init.d/iscsi restart

Now there should be a block device under /dev directory. To obtain new device name, type:
# fdisk -l
or
# tail -f /var/log/messages
Output:

Oct 10 12:42:20 ora9is2 kernel:   Vendor: EQLOGIC   Model: 100E-00           Rev: 3.2
Oct 10 12:42:20 ora9is2 kernel:   Type:   Direct-Access                      ANSI SCSI revision: 05
Oct 10 12:42:20 ora9is2 kernel: SCSI device sdd: 41963520 512-byte hdwr sectors (21485 MB)
Oct 10 12:42:20 ora9is2 kernel: sdd: Write Protect is off
Oct 10 12:42:20 ora9is2 kernel: SCSI device sdd: drive cache: write through
Oct 10 12:42:20 ora9is2 kernel: SCSI device sdd: 41963520 512-byte hdwr sectors (21485 MB)
Oct 10 12:42:20 ora9is2 kernel: sdd: Write Protect is off
Oct 10 12:42:20 ora9is2 kernel: SCSI device sdd: drive cache: write through
Oct 10 12:42:20 ora9is2 kernel:  sdd: unknown partition table
Oct 10 12:42:20 ora9is2 kernel: sd 3:0:0:0: Attached scsi disk sdd
Oct 10 12:42:20 ora9is2 kernel: sd 3:0:0:0: Attached scsi generic sg3 type 0
Oct 10 12:42:20 ora9is2 kernel: rtc: lost some interrupts at 2048Hz.
Oct 10 12:42:20 ora9is2 iscsid: connection0:0 is operational now

/dev/sdd is my new block device.

Step # 3: Format and Mount iSCSI Volume

You can now partition and create a filesystem on the target using usual fdisk and mkfs.ext3 commands:
# fdisk /dev/sdd
# mke2fs -j -m 0 -O dir_index /dev/sdd1

OR
# mkfs.ext3 /dev/sdd1

Tip: If your volume is large size like 1TB, run mkfs.ext3 in background using nohup:
# nohup mkfs.ext3 /dev/sdd1 &

Mount new partition:
# mkdir /mnt/iscsi
# mount /dev/sdd1 /mnt/iscsi

Step #4: Mount iSCSI drive automatically at boot time

First make sure iscsi service turned on at boot time:
# chkconfig iscsi on
Open /etc/fstab file and append config directive:
/dev/sdd1 /mnt/iscsi ext3 _netdev 0 0

블로그 이미지

유효하지않음

,

팀 스터디로 준비했던 PT 자료.
준비하다 보니 개념 자체보다는 이후의 동향이나 표준을 마련하는 부분 등이 더 중요하고 흥미롭기도 해서 다뤄 보고 싶었지만, 
일단 개념은 알아야 할 것 같아서 개념 설명에 대한 부분만 정리한 내용. 내용이 광범위하기도 하고.

결론적으로 클라우드 컴퓨팅이란 결국 새로운 기술이 아닌 현재 구현 가능한 다양한 기술들을 엮어 필요한 상태로 이용하기 위한 것. 각 사업자들의 동향이 특히 흥미로움. 그린 IT 이슈 등으로 앞으로 웹의 패러다임을 바꿀 기술이 될 듯..


블로그 이미지

유효하지않음

,

[출처]http://blog.naver.com/inter999/140060350540


클라우드 컴퓨팅(Cloud Computing)

 

클라우드 컴퓨팅 개념

클라우드 컴퓨팅 서로 다른 물리적인 위치에 존재하는 컴퓨터들의 리소스를 가상화 기술로 통합해 제공하는 기술을 말한다. , 개인용 컴퓨터나 기업의 서버에 개별적으로 저장해 두었던 프로그램이나 문서를 인터넷으로 접속할 있는 대형 컴퓨터에 저장하고, 개인 PC 물론이고 모바일 다양한 단말기로 브라우저 필요한 애플리케이션을 구동해 원하는 작업을 수행할 있는 이용자 중심의 컴퓨터 환경을 말한다. 아직까지 본격적인 클라우드 컴퓨팅이 이루어진 것은 아니지만, Google DOCs(Google), Work Space(Microsoft), Acrobat.Com(Adobe) 등에서 제한적으로 클라우드 컴퓨팅 서비스가 제공되고 있다.

 

클라우드 컴퓨팅 정의

"인터넷 기술을 활용하여 다수의 고객들에게 높은 수준의 확장성을 가진 IT 자원들을 '서비스' 제공하는 컴퓨팅." - 가트너

 

"표준화된 IT 기반 기능들이 IP 통해 제공되며, 언제나 접근이 허용되고, 수요의 변화에 따라 가변적이며, 사용량이나 광고에 기반한 과금모형을 제공하며, 혹은 프로그램적인 인터페이스 제공을 제시한다." - 포레스터 리서치

 

클라우드 컴퓨팅은 다양한 응용 프로그램들을 수용할 있는 관리되고 높은 확장성을 갖는 추상화된 컴퓨팅 인프라의 집합이라고 정의할 있다. 이러한 개념은 유틸리티 컴퓨팅이나 서비스로서의 소프트웨어(Software As A Service, SaaS), 그리고 그리드(Grid) 컴퓨팅 개념들이 혼합된 개념이다. , 하드웨어적인 또는 소프트웨어적인 컴퓨팅 자원을 사용한 만큼 비용을 지불한다는 사용자 측면에서는 유틸리티 컴퓨팅이나 SaaS 유사하고, 분산된 여러 컴퓨팅 자원을 취합하여 하나의 컴퓨팅 자원처럼 사용할 있도록 제공한다는 자원 제공자 측면에서는 그리드 컴퓨팅의 개념이라고 있다.

 

클라우드 서비스의 주요 특성

l  표준화된 IT 기반 기능

l  IP망을 통한 접근

l  Always on 수요에 따른 확장성 지원

l  사용량이나 광고기반 과금

l  Web 혹은 Programmatic 기반 Control Interface

l  사용자 셀프 서비스

 

클라우드 서비스 아키텍쳐

클라우드 컴퓨팅은 Web 2.0, Software as a service 같이 최근 알려진 기술 경향들과 연관성을 가지는 일반화된 개념이다. 이들 개념들의 공통점은 사용자들의 컴퓨팅 요구를 만족시키기 위해 인터넷을 이용한다는 사실이다. 예로서 Google Apps 있다. 브라우저로 이용할 있는 일반적인 비즈니스 응용프로그램들을 온라인으로 제공한다. 소프트웨어와 데이터는 서버에 저장된다.

사용자들은 서비스 제공자가 제공하는 서비스 카탈로그를 통해 원하느 서비스를 요청하고, 서비스 제공자의 시스템관리 모듈은 같은 요청에 대하여 가상화된 서버 네트워크를 통해 필요한 리소스를 조달하게 된다. 사용자들은 서비스를 이용만 어떻게 서비스가 제공되고, 자신의 데이터와 정보가 어디에 보관되는지, 어느 곳에 위치한 서버가 활용되는지 세부적인 정보는 알지 못한다.

사용자들은 어떤 장소에서든 인터넷 접속과 기본적인 연산기능만 있는 단말기를 가지고 있으면 인터넷을 통해 대용량의 저장장치와 고성능 컴퓨팅 리소스가 필요한 작업들을 수행하고, 고도화된 서비스들도 이용할 있게 된다. 이런 의미에서 클라우드 컴퓨팅은 향후 유비쿼터스 시대를 구현하게 핵심 컴퓨팅 환경으로 언급된다.

 

 

클라우팅 컴퓨팅과 컴퓨팅의 비교

 

주요개념

클라우팅 컴퓨팅과의 관계

Grid

Computing

높은 컴퓨팅 리소스를 필요로 하는 작업의 수행을 위해 인터넷 상의 분산된 다양한 시스템과 자원들을 공유하여 가상의 수퍼컴퓨터와 같이 활용하는 방식(분산 컴퓨팅 아키텍쳐)

Grid 방식의 분산 컴퓨팅과 Utility 개념의 과금모형을 혼합한 컴퓨팅 방식

그리드 : 인터넷상의 모든 컴퓨팅 리소스

클라우드 : 서비스제공 사업자의 사유서버 네트워크

Utility

Computing

컴퓨팅 리소스를 구매하거나 소유하지 않고, 가스, 전기 등과 같이 유틸리티로 필요할 마다 사용하는 방식(사용량 기반 과금 모형)

Server Base

Computing

서버에 어플리케이션과 데이터를 두고 필요할 때마다 접속해서 사용하는 방식(클라이언트는 ,출력만 처리. 모든 작업은 100% 서버가 처리-Thin Client 방식)

클라우드 컴퓨팅은 가상화된 분산 컴퓨팅에, SBC 특정 기업의 서버에 중심을 둔다는 차원에서 개념적으로 구분, 그러나 SBC 발전으로 점차 구분이 모호해

Network

Computing

SBC 비슷하나, 어플리케이션을 서버에서 로드하여 로컬에서 수행하는 형태(이용자의 CPU 사용하여 동작)

이용자의 컴퓨팅 리소스보다는 클라우드 상의 IT 리소스를 사용하므로 개념적 구분

SaaS

서비스 제공자의 서버에 저장된 SW 인터넷으로 통해 서비스로 이용하는 SW 딜리버리 모형

클라우드 컴퓨팅은 모든 IT자원을 서비스로 활용한다는 차원에서 보다 SaaS 포함하는 포괄적인 개념

 

클라우드 서비스 시장 유형

 

소비자 시장 유형 : 개인소비자(Web-based Service) 기업사용자(Software-as-a-service)

개인 소비자 시장은 블로그와 위치, 소셜네트워킹 서비스 등과 같이 웹기반 서비스 시장으로 광고기반 수익에 기반하는 시장. Google, MS, Yahoo 등의 많은 클라우드 서비스 제공자들은 소비자 시장을 중심으로 서장하고 있으며, 이를 기반으로 기업용 SaaS 시장으로 영역을 확장하고 있다.

기업사용자 시장은 기업의 IT 환경을 클라우드 환경으로 전환하고자 하는 기업들의 수요로 가입자 과금모형에 기반한 기업용 SaaS시장으로 볼수 있다. 클라우드 컴퓨팅이 초기 도입단계를 넘어 본격적인 성장단계로 진입하기 위해서는 기업시장이 중요한 역할을 한다.

 

SaaS 기술발전에 따른 시장전망

 

1세대

2세대

Challenge Gap

 

SOA 도입

기업프로세스 표준화

기존시스템과의 통합을 위한 중계표준

3세대

4세대

지원수준

기본적인 업무 프로세스 지원

데이터 관리를 포함하는 기능적 효율성 지원

기업내부 프로세스 통합지원

Business Ecosystem 지원

특성

단순 기능성을 제공하는 ASP

기본적인 커스터마이징 데이터 통합지원

고객 자원, 회사데이터 통합

부서간/파트너와의 협업프로세스 지원

도입 분야

세금, 회계관리 특수영역의 보편화된 서비스

CRM, 영업등 고객서비스 제공분야

고객/자원/데이터등 통합솔루션을 개별서비스관점에서 제공

복잡한 자원 접근 권한 관리 지원

 

IT 구매시장 : 어플리케이션 컴포넌트 서비스, 플랫폼 서비스, IT 인프라 서비스

클라우드 인프라를 활용하여 서비스를 재생산함으로써 웹을 기반으로 하는 비즈니스를 수행하고자 하는 개발자와 사업수요. 개발자들이 접근할 잇는 자원의 수준에 따라 어플리케이션 컴포넌트 서비스 시장, SW 플랫폼 서비스 시장, 가상인프라 서비스 시장으로 나룰 있다. 어플리케이션 컴포넌트 서비스는 개발자들을 위해 다양한 어플리케이션 모듈들을 제공하는 서비스로 Google 캘린더 API 세일즈포스닷컴의 AppExchange API등이 있다. 개발자들은 새로운 어플리케이션 개발을 위해 처음부터 개발을 하지 않고, 서비스 제공자가 제공하는 API 통해 신속하게 어플리케이션을 개발할 있다.

SW 플랫폼 서비스는 어플리케이션 API 제공수준을 넘어 미들웨어 까지 포괄적인 개발 플랫폼을 제공하는 서비스로, 세일즈포스닥컴의 Force.com 서비스가 대표적이다. 어플리케이션 개발 벤더들은 서비스 제공사업자가 제공하는 플랫폼 상에서 DB 어플리케이션 서버, 파일 관리 시스템과 관련한 솔루션 미들웨어까지 확장된 IT 자원을 활용하여 새로운 어플리케이션을 만들어 사용할 있다.

가상인프라 서비스는 개발자들과 IT기업들이 필요로 하는 가상의 IT 인프라자원을 포괄적으로 제공하는 서비스로 대표적으로는 아마존의 E2C서비스가 있다. 사용자들은 가상서버와 저장장치, 가상네트워크, 시스템관리 모든 가상의 자원들을 사용할 있고, 초기 인프라 구축비용 없이도 자신들의 비즈니스 모형을 구축하고, 웹을 통해 서비스를 제공할 있다.

 

주요 클라우드 서비스 비교

클라우드

서비스

아마존 EC2

Google App Engine

MS Live Mesh

분야

인프라

플랫폼

인프라

서비스유형

Computing & Storage(S3)

Web Application

Storage

가상화

OS Level running on a Xen Hypervisor

Application Container

OS Level

Qos 보장

미보장

미보장

미보장

사용자

인터페이스

EC2 Common-line Tools

웹기반 Admin, Console

웹기반 Live Desktop Live Mesh 설치된 모든 디바이스

Web API

제공

제공

미제공

부가서비스

제공

미제공

미제공

프로그램 Framewokr

리룩스기반 AMI(Amazon Machie Image)

Python

N.A

 

클라우드 서비스의 Pros & Cons

Pros

Cons

-       사용도가 낮은 IT 자원에 대한 자산구매를 회피하여 운영비용 절감

-       갑작스런 IT자원의 수용변화에 대한 저렴하고 신속한 대응 가능

-       필요한 자원의 선택적 구매와 사용량기반 대가 지불의 합리적인 가격모델

-       자산의 운영비화로 재무적 유연성 확보

-       해커와 외부 침입 공격 시스템 데이터보호 용이

-       클라우드 서비스의 안정성에 대한 우려

-       클라우드에 주요데이터와 정보를 저장하는데 따른 보안상의 우려

-       표준의 부족으로 인한 클라우드로의 전환 어려움

-       기존의 레거시 인프라로부터의 전화에 따른 기회비용 정확한 투자편익 계산의 어려움

 

클라우드 서비스 발전 조건

l  클라우드 서비스의 Qos보장과 SLA(Service Level Agreement) 제공

l  기업수요를 충족시킬 있는 어플리케이션/서비스의 고도화

l  Best Practice 기업 레퍼런스의 확대

l  주요 SW기업들의 적극적인 클라우드 서비스 시장 진출을 통한 경쟁 활성화

 

클라우드 컴퓨팅 사업자의 성공 조건

성공조건

배경

높은 브랜드 인지도

클라우드 서비스의 특성상 급작스런 서비스의 중단이나 사고로 인한 정보의 분실 등은 사용자들에게 중대한 손실을 야기할 있어, 서비스의 지속성과 안정성을 보장할 있는 높은 브랜드 인지도가 중요

IT 자원에 대한 규모의 경제 달성

클라우드 서비스 제공자는 막대한 물리적인 IT인프라 구축이 필수적, 따라서 이를 저렴하게 구축하고, 단위 인프라에 대한 효율성(단위 인프라당 평균사용자 이용도) 높이는 것이 핵심경쟁력으로, 이를 위해서는 규모의 결제 달성이 중요

높은 SW 기술력, 효율적인 자원관리 역량 검증된 서버운용 경험

IT 자원을 효율성을 극대화하면서도 사용자에게 안정적인 서비스를 제공하기 위해, 가변적인 사용자들의 서비스 요청을 최적화된 자원배분을 통해 실시간적으로 제공할 있는 고도화된 SW 기술력 필요, 특히 기업시장과 PassS전략을 추진하는 사업자들의 경우 플랫폼의 유연성과 안정성을 동시에 만족시킬 있는 기술력이 필수적

다양한 기업 솔루션 확보 초기시장 확보를 위한 마케팅 역량

현재 클라우드 서비스는 개인시장을 중심으로 성장하고 있으나, 본격적인 성장을 위해서는 기업시장으로 확산이 중요하며, 결국 기업시장을 대상으로 핵심적인 솔루션을 안정적으로 제공함으로써, 초기 시장을 선점하는 사업자가 향후 시장을 주도할 가능성이 높음

 

미국의 클라우드 컴퓨팅 이용 현황

미국의 Pew Internet & American Life Project 18 이상의 미국성인 2,251명을 대상으로 2008 4 8일부터 5 11일까지 조사한 결과에 따르면, 미국의 온라인 이용자들의 69% 웹메일 서비스, 온라인 데이터 저장서비스, 웹기반 워드프로세싱 애플리케이션과 같은 소프트웨어 프로그램 초기 형태의 클라우드 컴퓨팅 서비스를 이용하고 있는 것으로 조사되었다.

 


 



블로그 이미지

유효하지않음

,

DAS, NAS, SAN 개념정리

H/W 2009. 1. 22. 18:19
[출처] http://imgun.com/bbs/tb.php/study_etc/1

DAS [Direct Attached Storage]

서버와 전용 케이블로 연결한 외장형 저장 장치. 서버/클라이언트 환경에서의 부족한 저장 공간을 가장 쉽게 확보하는 방법으로 서버 자체에 물리적으로 외부 저장 장치를 연결하는 것이다. 네트워크에 연결된 각 서버에 외부 저장 장치를 추가함으로서 필요한 데이터를 물리적으로 가까운 곳에서 접근할 수 있고 확장이 용이하다. 하지만 데이터의 증가에 따른 외부 저장 장치의 계속적인 추가는 서버의 효율성을 저하시키는 문제가 있다. 또 다른 문제는 네트워크상의 서버가 다운되는 경우에는 중지된 서버에 장착된 저장 장치도 사용할 수 없게 되어 중앙 집중식 시스템과 같은 취약점이 있다.
 

 

NAS [Network Attached Storage]

File Server는 파일공유와 파일 서비스라는 서버로서의 기능으로부터 시작된 솔루션이다. 네트워크가 발달하지 못하고 데이터 양이 많지않던 시절에 부서별로 파일공유를 위해 또는 파일에 대한 관리의 편의를 위해 시작되었던 솔루션으로 파일공유 및 파일 서비스 기능을 위해서는 범용OS (Unix 또는 Windows NT)에서 제공되는 일부분의 기능(NFS 또는 CIFS)을 이용하였고 데이터 저장장치는 주로 서버에 내장된 디스크를 사용하였다. 그리고 서버/클라이언트 구조로 파일서버가 서버로서의 역할을 각 End-user의 단말(PC 또는 Workstation)이 클라이언트로서의 역할을 하도록 구현되었다. 그런데 세월이 흐르면서 사용자 환경이 변하였다. 파일공유 및 파일 서비스를 위한 데이터 용량이 폭증하였다는 점, 변화는 파일공유 및 파일서비스를 위한 I/O가 보다 높은 대역폭과 속도를 요구한다는 점이다.
파일서버의 한계를 극복한 것이 NAS(Network Attached Storage)이다. NAS는 저장장치의 기능을 강조한 것으로 저장장치 부분의 하드웨어적 성능/기능뿐 아니라 소프트웨어적 기능이 예전의 파일서버와는 차별화 되었다. 그리고 I/O측면에서도 범용 OS대신에 파일서비스에 특화된 전용의 OS를 채용함으로써 보다 나은 I/O 성능을 제공하고 있다. 그리고 역할에 있어서도 기존의 파일서버가 End-user 단말에 대한 파일서비스를 제공하는 역할을 강조한 반면 NAS End-user단말에 대한 기존 파일서버의 역할뿐만 아니라 애플리케이션 서버의 데이터를 네트웍(LAN)을 통해 저장하여 네트웍이 연결된 곳에서는 언제 어디서라도 스토리지를 접속해서 사용할 수 있는 애플리케이션 서버에 대한 저장장치로서의 역할도 하고 있다
NAS를 이름 그대로 해석해 보면 네트웍(LAN)에 접속된 스토리지이다. 과연 스토리지를 LAN에 붙일수 있을까? 말을 바꾸어 보자. 스토리지는 SCSI 프로토콜을 기반으로 통신을 하고 LAN TCP/IP 프로토콜을 기반으로 통신을 한다.
 


 
NAS 장점은 파일공유다. 여러 애플리케이션 서버들이 LAN 통해 NFS또는 CIFS 같은 파일 서비스 프로토콜로 전용파일서버에 접속하여 파일에 대한 서비스를 요청하면 단일 파일서버가 요청에 따라 파일서비스를 하게 되므로써 NAS 저장된 파일이 모두 전용파일서버 한곳에서 관리됨으로써 파일들에 관한 정보들의 Consistency라든가 locking 문제가 없이 파일을 여러 서버들이 공유할 있게 된다.
NAS의 단점은 성능과 DB에서 사용할 때의 문제점이다. 성능상의 단점중의 한 요인은 Latency Time이다. NAS는 애플리케이션 서버에서 전용파일서버까지 네트웍으로 접속되고 전용파일서버에서 스토리지사이는 채널로 접속되어 채널로만 접속되는 DAS또는 SAN에 비해 접속단계가 늘어남으로서 Latency Time이 더 걸리게 된다. 물론 NAS LAN에서의 Latency time에서 단점을 Cache에서 그리고 저장장치 부문에서의 성능으로 보충하여 JBOD(Just Bunch of Disk: 저급의 디스크 스토리지를 의미)나 성능이 떨어지는 내장형 Disk보다 빠를 수 있다. 그러나 동급의 디스크 스토리지로 비교했을때는 DAS SAN보다 성능이 조금 떨어지는 것이 보통이다. 특히 I/O가 많은 대용량의 DB인 경우, 그리고 대규모 Batch Job을 수행해야 하는 경우에는 이와같은 성능차이가 문제가 된다. 또한 DB의 경우 전용 파일서버에서의 Caching기능 때문에 전용파일서버에 장애가 일어난 경우 Data consistency가 문제가 될 수도 있다.

SAN [Storage Area Network]

'광저장장치영역네트워크'로 번역되고 '스토리지 에어리어 네트워크'라고도 한다. 특수 목적용 고속 네트워크로서, 대규모 네트워크 사용자들을 위하여 서로 다른 종류의 데이터 저장장치를 관련 데이터 서버와 함께 연결해 별도의 랜(LAN:근거리통신망)이나 네트워크를 구성해 저장 데이터를 관리한다.
정보기술(IT)이 급속히 발전하면서 기업들의 가장 큰 고민 가운데 하나는 많은 데이터를 어떻게 효율적으로 저장할 수 있는가 하는 것이었다. 기존저장 방법은 장비에 스토리지를 붙여서 쓰는 DAS(direct attached storage:직접연결스토리지)를 이용하였으나, 저장할 데이터와 늘어나는 데이터가 한 공간에 존재하므로 데이터의 전송 속도가 떨어지는 단점이 있다. SAN은 이러한 단점을 극복하기 위한 목적으로 1990년대 말부터 개발되기 시작해 채 몇 년도 안 되어 새로운 데이터 저장기법으로 떠올랐다. 서로 다른 종류의 저장장치들이 함께 연결되어 있어 모든 사용자들이 공유할 수 있을 뿐 아니라, 백업·복원·영구보관·검색 등이 가능하고, 한 저장장치에서 다른 저장장치로 데이터를 이동시킬 수 있다는 장점이 있다. SAN 외에 별도로 랜이나 네트워크를 구성해 저장 데이터를 관리하는 방법으로 NAS(network attached storage:네트워크연결스토리지) 등이 있지만, 2002년 현재 SAN 기법이 보편화되어 시장의 50% 이상을 차지하고 있다. 더욱이 갈수록 대형화하면서 고성장세를 보이고 있다.
하지만 SAN 을 구축하기 위해서는 NAS 스토리지에 비해서 많은 비용과 장비들의 투자가 필요하고, 기존 시스템들의 업그레이드가 필수적이므로 몇가지 제약이 있다.
SAN 을 이기종간의 여러 서버에서 하나의 스토리지를 공유하기 위해서는 SAN 메니지먼트 소프트웨어가 별도로 필요로 하고 , NAS 와는 달리 SAN 네트워크를 별도로 구축을 해야 한다는 단점이 있다.
SAN은 서버와 스토리지 사이의 채널 접속에 파이버 채널 스위치를 넣어 네트웍의 개념을 도입한 것이다. 그렇다면 왜 SCSI Switch가 아닌 파이버채널 스위치인가? SCSI의 경우 Open System의 채널 인터페이스이긴 하지만 접속 거리가 최대 25m로 네트웍으로 구성하기에는 거리제약이 있으며 스위칭을 위한 고려가 전혀 되어있지 않는 인터페이스란 점 때문에 파이버 채널을 SAN의 표준으로 정하게 되었다.
파이버 채널 스위치를 중간에 넣음으로서 서버의 접속 포트 하나에서 여러대의 스토리지를 접속할 수 있고 또한 스토리지의 접속 포트 하나에 여러 서버가 접속할 수 있는 유연성이 생기게 된다. 그러나 여러 서버에서 파일 공유를 하려는 측면에서 생각해 보면 동일 파일 시스템에 대한 관리를 각각의 서버에서 해야 하기 때문에 Locking 문제와 Consistency 문제가 생기게 되고 그런 이유로 파일공유가 되지 않는다. 그렇다면 SAN에서 말하는 공유는 무엇일까? 그것은 지금현재로는 서버측면에서의 스토리지 공유 또는 스토리지 측면에서의 서버 공유를 의미할 뿐이다. 물론 SAN에서 궁극적으로 추구하는 목표에는 파일시스템의 공유가 포함되어 있으며 그러한 노력이 현재 진행되는 있는 것은 사실이지만 파일시스템의 공유라는 목표를 달성하기에는 아직도 많은 시간이 필요하리라고 생각된다
 

 

비교자료

NAS File Server 비교

 
NAS
File Server
관점
스토리지
서버
역할
파일서버, 스토리지로서의 역할
파일서버 역할
저장장치형태
전용 OS
범용 OS
가용성
저장된 정보의 무중단 활용 측면에서의 가용성을 중시
정보 보호 보다는 파일서비스와 파일공유 기능에 중점
파일서버 성능
보통
데이터 용량
500GB 이상
200GB이하
파일 서비스를 위한 프로토콜
NFS, CIFS 동시 지원
사용 OS에 따라 NFS, CIFS 지원

NAS SAN 비교

 
NAS
SAN
구성요소
어플리케이션 서버, 전용 파일 서버, 스토리지
어플리케이션 서버, 스토리지
접속장치
LAN 스위치
Fibre Channel 스위치
스토리지 공유
가능
가능
파일시스템 공유
가능
불가능
파일시스템 관리
파일서버
어플리케이션 서버
접속 속도 결정 요인
LAN과 채널 속도에 좌우됨
채널 속도에 좌우됨
비고
파일공유를 위한 전통적 솔루션
유연성, 확장성, 편의성이 가장 뛰어난 구성

DAS, NAS, SAN 비교

 
DAS
NAS
SAN
구성요소
어플리케이션 서버, 스토리지
어플리케이션 서버, 전용파일 서버, 스토리지
어플리케이션 서버, 스토리지
접속장치
없음
이더넷 스위치
파이버채널 스위치
스토리지
공유
가능
가능
가능
파일시스템
공유
불가능
가능
불가능
파일시스템
관리
어플리케이션 서버
파일 서버
어플리케이션 서버
접속 속도
결정요인
채널속도
LAN과 채널속도
채널속도
특징
소규모 독립된 구성에 적합
파일 공유를 위한 가장 안정적이고 신뢰성 높은 솔루션
유연성/확장성/편의성이 가장 뛰어남
 

용어 : Fibre Channel

SAN(Storage Area Network)에 사용되는 표준화 채널로서 FWU(Fast Wide Ultra) SCSI의 뒤를 이을 차세대 고속 인터페이스다. 1992년에 휼렛패커드와 선마이크로시스템스•IBM 3개 업체가 FCSI(Fibre Channel Systems Initiative)를 구성했고, IP SCSI의 공조에 관심을 두고 표준화 작업을 진행하여 1998년에 표준안이 마련되었다. 2003년 현재 FCA(Fibre Channel Association) FCLC (Fibre Channel Loop Community)에서 관리한다.
FWU SCSI보다 4∼5배 빠른 1Gbps의 속도로 데이터를 전송할 수가 있으며, 사용되는 프로토콜이 SCSI와 호환되어 기존의 장치를 그대로 사용할 수 있는 장점이 있다. 또 거리 제한도 거의 없어 서버나 JBOD(Just a Bunch Of Disks; RAID 기능이 없는 하드디스크드라이브 세트)를 데이터센터에서 최대 8.6㎞나 떨어진 곳에 설치할 수도 있다. 설치 거리는 점차 늘어날 것으로 보인다.
이 기술로 백본랜을 구축할 경우, 수백 테라바이트의 용량을 보유한 중앙집중식 저장장치 팜(Farm)을 구축할 수 있고, 재해 복구를 위한 외부의 미러링도 가능하다. 클라이언트/서버 컴퓨팅에서 요구되던 분산 아키텍처를 지원하고, 폴트톨러런스(Fault Tolerance)와 자체 복구 기능도 지녀 네트워크 연결을 유연하게 해 준다. , 네트워크 확장을 거의 무한대 수준으로 끌어올리는 등 네트워크의 성능 저하를 최소화시킨다.
블로그 이미지

유효하지않음

,