독까의 이야기

MS-SQL 2008 ENT 이상 버전에서 지원되는 TDE 기능에 대한 테스트를 진행 한다. 
STD 에서도 복원은 가능하나, DB 는 사용 할 수 없다. 

OS : Windows 2016
DBMS : MS-SQL 2014 ENT

1. DB 생성
DB 명 : gunnm 
USE master;
CREATE DATABASE [gunnm]
ON
( NAME = gunnm, FILENAME = 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm.mdf')
LOG ON
( NAME = gunnm_log, FILENAME = 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm_log.ldf')
GO




2. 암호화 진행

마스터 키 생성
USE master
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'PassWord!2#'
GO

마스터 키로 보호 된 인증서 생성
CREATE CERTIFICATE gunnm_cert WITH SUBJECT = 'gunnm_cert'
GO

마스터 키 백업
USE master
BACKUP SERVICE MASTER KEY TO FILE = 'H:\service_master.key' ENCRYPTION BY PASSWORD = 'Service_PW@1119'
GO
BACKUP MASTER KEY TO FILE = 'H:\db_master.key' ENCRYPTION BY PASSWORD = 'DB_PW#1119'
GO

DB 암호화 키 생성
USE gunnm
GO
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE gunnm_cert 
GO

실행 메시지 
경고: 데이터베이스 암호화 키를 암호화하는 데 사용된 인증서가 백업되지 않았습니다. 인증서와 인증서에 연결된 개인 키를 즉시 백업해야 합니다. 인증서를 사용할 수 없게 되거나 다른 서버에서 데이터베이스를 복원하거나 연결해야 할 경우 인증서와 개인 키의 백업본이 있어야 합니다. 그렇지 않으면 데이터베이스를 열 수 없습니다.

DB 암호화 적용
USE gunnm
GO
ALTER DATABASE gunnm
SET ENCRYPTION ON
GO

DB 암호화 키 백업
USE master
BACKUP CERTIFICATE gunnm_cert TO FILE = 'H:\gunnm_cert.cer' WITH PRIVATE KEY ( FILE = 'H:\gunnm_cert.pvk' , ENCRYPTION BY PASSWORD = 'gunnm_PW$1119' )
GO

DB 백업
BACKUP DATABASE [gunnm] TO  DISK = 'H:\gunnm.bak';
GO



3. 대상 서버에서 DB 복원 진행

원본 서버에서 생성 된 DB 인증서 파일 (.cer / .pvk) 및 DB 백업 파일 (.bak) 을 복사한다. 

마스터 키 생성 : 원본 서버와 동일한 패스워드를 입력할 필요는 없다. 
USE master
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'PassWord1@3'
GO
CREATE CERTIFICATE gunnm_cert WITH SUBJECT = 'DB_Enc'
GO

원본 서버 인증서 파일을 통한 인증서 생성 및 DB 복원
CREATE CERTIFICATE gunnm_cert
  FROM FILE = 'H:\gunnm_cert.cer'
  WITH PRIVATE KEY ( 
    FILE = 'H:\gunnm_cert.pvk',
 DECRYPTION BY PASSWORD = 'gunnm_PW$1119'
  );

실행 메시지 : 
메시지 15232, 수준 16, 상태 1, 줄 2
이름이 'gunnm_cert'인 인증서가 이미 있거나 이 인증서가 데이터베이스에 이미 추가되었습니다.
테스트이므로 서버간 이동을 하지 않고, 동일 서버에서 진행되어 발생 된 오류로 추정

-- 등록 인증서 제거
USE master; 
DROP CERTIFICATE gunnm_cert;


CREATE CERTIFICATE gunnm_cert
  FROM FILE = 'H:\gunnm_cert.cer'
  WITH PRIVATE KEY ( 
    FILE = 'H:\gunnm_cert.pvk',
 DECRYPTION BY PASSWORD = 'gunnm_PW$1119'
  );

RESTORE DATABASE [gunnm]
  FROM DISK = 'H:\gunnm.bak'
  WITH MOVE 'gunnm' TO 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm.mdf',
       MOVE 'gunnm_log' TO 'D:\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\gunnm_log.ldf';
 



4. TDE 모니터링 스크립트
SELECT DB_NAME(database_id) AS DatabaseName, encryption_state,
encryption_state_desc =
CASE encryption_state
         WHEN '0'  THEN  'No database encryption key present, no encryption'
         WHEN '1'  THEN  'Unencrypted'
         WHEN '2'  THEN  'Encryption in progress'
         WHEN '3'  THEN  'Encrypted'
         WHEN '4'  THEN  'Key change in progress'
         WHEN '5'  THEN  'Decryption in progress'
         WHEN '6'  THEN  'Protection change in progress (The certificate or asymmetric key that is encrypting the database encryption key is being changed.)'
         ELSE 'No Status'
         END,
percent_complete,encryptor_thumbprint, encryptor_type  FROM sys.dm_database_encryption_keys 


USE master
GO
SELECT * FROM sys.certificates

-- encryption_state = 5 is encrypted
SELECT * FROM sys.dm_database_encryption_keys
WHERE encryption_state = 3; 



5. 암호화 제거

DB 암호화 비활성화
USE gunnm
ALTER DATABASE gunnm SET ENCRYPTION OFF
GO

DB 암호화 키 제거
USE gunnm
GO
DROP DATABASE ENCRYPTION KEY  

마스터 키 및 인증서 제거
-- 마스터 키 제거
USE master;
drop master key;
GO

-- 등록 인증서 제거
USE master; 
DROP CERTIFICATE gunnm_cert;
GO  



MS-SQL DB 를 이용하는 서버의 CPU 사용량이 100% 가 출력되어 점검을 진행했다.


윈도우에서 성능 모니터에 카운터 추가를 해서 했는데 손이 너무 많이 간다. 


성능 모니터에서 카운터 추가

성능 개체 : Thread

카운터 : % Processor Time / ID Thread 

인스턴스 : sqlservr 리스트 전체 선택

CPU 사용량이 높은 SQL 스레드 ID 확인 : 4280

스레드 ID 로 spid 확인 

SELECT spid, kpid, dbid, cpu, memusage FROM sysprocesses WHERE kpid=4280

SPID : 240

spid 로 쿼리문 확인 

dbcc inputbuffer (240)


이렇게 했는데, 일을 두 번 할 필요는 없으니깐, SSMS 에서 한 번에 확인이 가능한 방법을 검색해서 정리해 보았다. 

SSMS 에 접속, tempdb 에서 새쿼리 실행 후 진행을 한다. 

그러면 tempdb 의 임시 테이블에 해당 테이블이 저장이 되는데, 다 확인하고 나면 맨 하단 drop 명령어로 테이블 제거를 하면 된다. 

use tempdb
CREATE TABLE #sp_who2 (SPID INT,Status VARCHAR(255),
      Login  VARCHAR(255),HostName  VARCHAR(255),
      BlkBy  VARCHAR(255),DBName  VARCHAR(255),
      Command VARCHAR(255),CPUTime INT,
      DiskIO INT,LastBatch VARCHAR(255),
      ProgramName VARCHAR(255),SPID2 INT,
      REQUESTID INT)
INSERT INTO #sp_who2 EXEC sp_who2
SELECT      *
FROM        #sp_who2
-- Add any filtering of the results here :
WHERE       Status = 'RUNNABLE'
-- Add any sorting of the results here :
ORDER BY    CPUTime ASC

CPU 사용량이 높은 spid 가 확인 됐으면, dbcc inputbuffer (SPID) 를 실행하여 쿼리문을 확인하면 된다. 

다 완료 되었으면 아래의 명령어를 통해 임시 테이블을 제거 한다. 

DROP TABLE #sp_who2


# 현재 실행 중인 쿼리문 확인하는 명령어

SELECT
   sqltext.TEXT,
   req.session_id,
   req.status,
   req.command,
   req.cpu_time,
   req.total_elapsed_time
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext 


위에 생성 된 임시테이블의 select 구문과 현재 실행 중인 쿼리문을 조회하는 실행문을 동시에 실행해서 일치하는 spid 를 찾는 것도 좋은 방법일 것 같다. 



리눅스 서버와 윈도우 서버에 mysql 을 설치 했으니, 이중화를 구성하려고 한다.

MS-SQL 이중화와는 방식이 다르긴 하지만 뭐, 그냥 저냥 해보면 될 것 같다. 


1.  Master 와 Slave 할당


검색을 통해서 알아보니깐 DB 버전이 완전히 같을 필요는 없지만, Slave 가 버전이 높아야 한다고 한다. 


그래서 Master 는 리눅스 mysql 5.1 을, Slave 는 윈도우 mysql 5.6 으로 정했다. 


M : Linux / mysql 5.1 / 192.168.1.10

S : Window / mysql 5.6 / 192.168.1.20




2.  M 의 my.cnf 설정 추가


[mysqld] 하단에 아래의 구문 추가


log-bin=mysql-bin

server-id = 1


mysqld 서비스 재시작


# service mysqld restart




3.  M 의 mysql 에 S 에서 접속할 사용자 계정 생성


mysql> use mysql;

mysql> grant replication slave on *.* to 'repluser'@'192.168.1.20' identified by 'password';




4.  S 의 my.ini 설정 추가


[mysqld] 하단에 아래의 구문 추가


log-bin=mysql-bin

server-id = 2


윈도우 서비스에서 mysql 재시작




5.  S 에서 M 에 접속하는 정보 등록


my.ini 에 아래와 같이 구문을 추가 하고, 서비스 재시작 했더니 구동 실패가 발생했다.


[mysqld] 

master-host=192.168.1.10

master-user=repluser

master-password=password

master-port=3306


mysql 에서 직접 M 의 접속 정보 입력을 진행 했다. 


mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10',MASTER_USER='repluser',MASTER_PASSWORD='password', MASTER_PORT=3306, MASTER_CONNECT_RETRY=30;

mysql > start slave;


하고 나면, my.ini 에 해당 설정이 추가 되는게 아니라  C:\ProgramData\MySQL\MySQL Server 5.5\data\master.info 파일이 생성되어 저장 된다. 


윈도우 환경이라서 다른 것일 수도 있다. (리눅스 끼리 연동 후 확인 필요)




6.  M 의 mysql 에서 replication 작동 상태 확인


mysql> show master status;




7.  S 의 mysql 에서 replication 작동 상태 확인


mysql> show slave status;




8.  M 의 mysql 에 접속하여 테이블 생성 및 데이타 입력


mysql> use test;

mysql> create table gunnm ( no int(5), date int(10), text char(50), primary key(no) );

mysql> insert into gunnm values ('1', '20180321', 'replication test success, gunnm.tistory.com');

mysql> select * from gunnm;




9.  S 의 mysql 에 접속하여 gunnm 테이블 조회


mysql> use test;

mysql> select * from gunnm;




10.  결과

MS-SQL 의 미러링을 구성하는 Slave 서버에서는 대부분의 기능이 제한적인데 반해, mysql 에서는 slave 이지만 데이타값 조회가 가능한 것을 확인했다. 

그래서 slave 에서 데이타를 입력하면 master 에도 반영이 되는가를 테스트 해보았는데, 결과는 


master 의 테이블에는 slave 에서 입력한 데이타값 저장이 되지 않았다. 



결과적으로 Master 로 부터 데이타를 가져와서 저장을 하지만, 양방향 동기화가 되는 것은 아니다. 

즉, Master 에서 Slave 로의 데이타 백업만 진행되는 것을 확인 했다. 

구성 방식을 바꾸면 가능한지를 확인해 봐야겠다. 


OS 가 상이하여도 (리눅스 + 윈도우), mysql 을 DBMS 로 사용 한다면 이중화 구성이 가능함을 확인했다.