2023年11月10日 星期五

如何透過 Partition Table 進行資料分散與維護作業並以年度為例

        先前一篇針對 Partition Table 進行詳細的介紹,近日再重新的檢示,其實我覺得自已當初提出的資料平均分配的方式很好,而且其實到現在還是很適用,但由於有很多的客戶需求,希望可以透過日期的方式來進行資料分散與切割,所以今天我就透過這篇來特別介紹一下。

如何在 AlwaysOn 建立 Partition Table 與自動進行資料平均分配http://caryhsu.blogspot.com/2016/01/alwaysonpartition-table.html

此篇我們透過 AdventureWorks 的資料庫來進行,並且也會說明在建立後,如果遇到新年度時,大佬與預算較緊的使用者們,針對透過年月的方式進行資料分散的方式,該如何維護,這篇也會詳細的介紹。

本篇在 Partition Table 建立後,其實維護是最麻煩的,由其在 Merge 與 Split 的部份,我其實也是在測試機上測試了好多次,才摸清最好與最佳的方式,希望二篇加起來後,可以更完整的幫助到大家。

1。 加入 file group 與 files,這邊建議將 file 分散至不同的卷上面,最好的情況是有四台實體磁碟,各自放一個 file。

USE [master]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILEGROUP [ag_group_1]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILEGROUP [ag_group_2]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILEGROUP [ag_group_3]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILEGROUP [ag_group_4]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILE ( NAME = N'fg_1', FILENAME = N'C:\sql_data\fg_1.ndf' , SIZE = 51200KB , FILEGROWTH = 1024KB ) TO FILEGROUP [ag_group_1]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILE ( NAME = N'fg_2', FILENAME = N'C:\sql_data\fg_2.ndf' , SIZE = 51200KB , FILEGROWTH = 1024KB ) TO FILEGROUP [ag_group_2]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILE ( NAME = N'fg_3', FILENAME = N'C:\sql_data\fg_3.ndf' , SIZE = 51200KB , FILEGROWTH = 1024KB ) TO FILEGROUP [ag_group_3]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILE ( NAME = N'fg_4', FILENAME = N'C:\sql_data\fg_4.ndf' , SIZE = 51200KB , FILEGROWTH = 1024KB ) TO FILEGROUP [ag_group_4]
GO

2. 由於目前有四個資料群組,所以我們先統計一下資料量,然後再來規畫一下如何分散資料,目前如下圖,主要有2013年7月至2014年8月的資料。

--統計資料分佈

SELECT left(convert(varchar,TransactionDate,112),6) [tdhyear], count(*) nums
FROM [AdventureWorks2019].[Production].[TransactionHistory]
group by  left(convert(varchar,TransactionDate,112),6)
order by 1,2


3. 建立 Partition Function 與 Partition Schema,這邊會建立三個區域與對應至四個 File Group,如下列所示。

1900-01-01 00:00:00.000 ~ 2013-10-01 00:00:00.000 -> 儲存至 ag-group_1
2013-10-01 00:00:00.000 ~ 2014-02-01 00:00:00.000 -> 儲存至 ag-group_2
2014-02-01 00:00:00.000 ~ 2014-04-01 00:00:00.000 -> 儲存至 ag-group_3
2014-04-01 00:00:00.000 ~ 日後所有 -> 儲存至 ag-group_4

--將資料平均分散在多個不同區間

use [AdventureWorks2019];
CREATE PARTITION FUNCTION [PF-cary-test](datetime) AS RANGE RIGHT FOR VALUES (N'2013-10-01T00:00:00', N'2014-02-01T00:00:00', N'2014-04-01T00:00:00')

PS: 這裡建議採用 RANGE RIGHT 的方式,而不是用 RANGE Left, 因為我在 SQL Server 2019 與 2022 上測試,當使用 RANGE Left 的方式時,如果進行 SPLIT RANGE時,你會發現 ALTER PARTITION SCHEME 中的 NEXT USED 當合併資料,並將新加入的 file 與前一個 file 互換,雖然這樣也是沒問題,但還是覺得怪怪的,所以這邊也再請注意一下。

CREATE PARTITION SCHEME [PS-cary-test] AS PARTITION [PF-cary-test] TO ([ag_group_1], [ag_group_2], [ag_group_3], [ag_group_4])

4. 建立完上述的動作後,資料並不會立即的進行資料的搬移,需透過移除 Clustered Index 後,再將索引重新加入後即可

此處原本 TransactionID 是 PK 與 CLUSTERED INDEX,但由於此處的 Partition Table 是根據 TransactionDate 進行分配,所以要將 CLUSTERED INDEX 換成 TransactionDate 之後,資料才會重新進行排序。

ALTER TABLE [Production].[TransactionHistory] DROP CONSTRAINT [PK_TransactionHistory_TransactionID] WITH ( ONLINE = OFF )

ALTER TABLE [Production].[TransactionHistory] ADD  CONSTRAINT [PK_TransactionHistory_TransactionID] PRIMARY KEY NONCLUSTERED
(

[TransactionID] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]

CREATE CLUSTERED INDEX [ClusteredIndex_on_PS-cary-test_638351445508081513] ON [Production].[TransactionHistory]
(

[TransactionDate]

)WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PS-cary-test]([TransactionDate])

DROP INDEX [ClusteredIndex_on_PS-cary-test_638351445508081513] ON [Production].[TransactionHistory]

5. 透過下列的語法進行查詢,並確認資料在各群組分配的情況

SELECT OBJECT_NAME(p.object_id) AS ObjectName ,
i.name AS IndexName ,p.index_id AS IndexID ,
ds.name AS PartitionScheme ,
p.partition_number AS PartitionNumber ,
fg.name AS FileGroupName ,
prv_left.value AS LowerBoundaryValue ,
prv_right.value AS UpperBoundaryValue ,
CASE pf.boundary_value_on_right
WHEN 1 THEN 'RIGHT'
ELSE 'LEFT'
END AS PartitionFunctionRange ,
p.rows AS Rows
FROM sys.partitions AS p
INNER JOIN sys.indexes AS i ON i.object_id = p.object_id
AND i.index_id = p.index_id
INNER JOIN sys.data_spaces AS ds ON ds.data_space_id = i.data_space_id
INNER JOIN sys.partition_schemes AS ps ON ps.data_space_id = ds.data_space_id
INNER JOIN sys.partition_functions AS pf ON pf.function_id = ps.function_id
INNER JOIN sys.destination_data_spaces AS dds ON dds.partition_scheme_id = ps.data_space_id
AND dds.destination_id = p.partition_number
INNER JOIN sys.filegroups AS fg ON fg.data_space_id = dds.data_space_id
LEFT OUTER JOIN sys.partition_range_values AS prv_left ON ps.function_id = prv_left.function_id AND prv_left.boundary_id = p.partition_number- 1
LEFT OUTER JOIN sys.partition_range_values AS prv_right ON ps.function_id = prv_right.function_id AND prv_right.boundary_id = p.partition_number
WHERE p.object_id = OBJECT_ID('Production.TransactionHistory');


6。 從查詢上來看,後續未規畫的資料年度就會放置到最後一個 file group,所以當新年度到達時,通常我們會採取二種不同的作法,一時加入一個 file group,然後將後續的資料加入,另一種就是合併資料,並將新年度的資料轉向最後一個 file group中,所以也在這分別說明二種方式。

7。 課長級作法。也就是加入一個 file 並將新年度的資料轉至此新的 file 中

7-1. 加入新的 file group

use [master];
ALTER DATABASE [AdventureWorks2019] ADD FILEGROUP [ag_group_5]
GO

ALTER DATABASE [AdventureWorks2019] ADD FILE ( NAME = N'fg_5', FILENAME = N'C:\sql_data\fg_5.ndf' , SIZE = 51200KB , FILEGROWTH = 1024KB ) TO FILEGROUP [ag_group_5]
GO

7.2 將新的 file group 加入至 schema 中,並分割出新的資料區間時區,就是將 '2015-01-01' 後的時間,儲存至新的 file 中

use [AdventureWorks2019];
ALTER PARTITION SCHEME [PS-cary-test]
NEXT USED ag_group_5;

ALTER PARTITION FUNCTION  [PF-cary-test] () 
SPLIT RANGE ('2015-01-01T00:00:00.000')

7-3 查詢資料分佈的情況

8. 微課長級的作法,如果無法增加新的 file 用來分散資料的話,可以透過資料合併的方式,然後將新的資料儲存至最後一個群組中

8-1 依照資料上的分佈,我先將 file 3 與 4 的資料先進行合併,所以這邊我將 2014-02-01 00:00:00.000 之後的資料先合併至 ag-group3

ALTER PARTITION FUNCTION [PF-cary-test] () 
MERGE RANGE ('2014-04-01 00:00:00.000');

8-2 將 2015-01-01 之後的資料存到 ag-group4 上面

ALTER PARTITION SCHEME [PS-cary-test]
NEXT USED ag_group_4;

ALTER PARTITION FUNCTION  [PF-cary-test] () 
SPLIT RANGE ('2015-01-01T00:00:00.000'); 

8-3 由於有作過資料合併的動作,所以最好也是手動更新一次統計資訊

UPDATE STATISTICS [Production].[TransactionHistory]

8-4 查詢資料分佈的情況

2023年11月8日 星期三

SQL Server 啟動帳號最佳實踐與最小化權限設定

        此篇文章主要是最近經過二位大師的指導,修正一些以前的概念,自已嘗試作過一次後,發現其中其實有許多的坑,沒有作過一次,真的很難說有 100% 的懂 (我自已),而且作完後有更深的體驗,所以整理成此篇,相信這也是企業內日後主推的部份,也希望大家可以參考並套用在企業中。        

預設的情況下,SQL Server 的啟動帳號為 NT Service\MSSQLSERVER,而在網域的架構上,許多人會設定為網域帳號,如常見的 Domain User + Local Admin,但這樣的設定在安全性與稽核上,存在著許多的問題。

在許多的公司,常見的情況,通常會規定不能使用 Local Admin,而且規定每一個帳號 60 or 90 天後要重新設定密碼,所以以前常遇到客戶提出SQL重啟後,無法正常啟動,常見遇到的就是密碼過期等情況,所以造成無法啟動。

另外如果 SQL Server 的啟動帳號權限設定的太大,一但遇到如 SQL Injection 等的攻擊時,容易會造成更大的問題,因為會被當作跳板,再進行其他主機的攻擊,所以最小化的權限設定,將可以有效的防止等問題的發生。

最後許多的系統管理員要維護自已的帳號與密碼於 Excel or 筆記本中,而且在固定的時間就要進行更新,這種明碼存在的方式,也是另一個安全性的隱憂。

講了這麼多,我們就講主題,在啟動帳號的部份,微軟 (Microsoft) 強烈的推薦透過 受控服務帳戶 (Managed Service Accounts) 與 群組受控服務帳戶 (Group Managed Service Accounts) 來進行,如同我上述的介紹,這二個帳號類型就符合我提到的部份,在使用這二個帳號類型前,我們也來說看一下最低限制。

Group Managed Service Account Prerequisites:

  • Domain Functional Level of 2012 or higher
  • SQL Server 2014 or higher
  • Window Server 2012 R2 Operating System

另外受控服務帳戶 (Managed Service Accounts) 與 群組受控服務帳戶 (Group Managed Service Accounts) 在設定上,也不需要手動輸入密碼,不需要再透過 Excel 等筆記本來記錄帳號密碼等,而密碼的部份也是每30天自動更新,二個帳號一個應用於單機的環境,而另一個則是應用於 HA 等的架構,如 WSFC、AlwaysOn 等群組節點的情境,所以本篇將透過  群組受控服務帳戶 (Group Managed Service Accounts) 與 AlwaysOn 的環境來進行設定。

1. 登入主要網域進行下列的設定

2. 首先檢查 KDS (Key Distribution Service) 是否有 Root Key 的存在。 

Test-KdsRootKey -KeyId (Get-KdsRootKey).KeyId

如果存在的話,會傳回 "True",如果沒有的話,就需要進行下列設定。

Add-KdsRootKey –EffectiveTime ((get-date).addhours(-10))
or
Add-KdsRootKey -EffectiveImmediately

3. 也可以透過下列的指令查詢目前所有的 KDS KEY

Get-KdsRootKey

4. 建立一個群組,並將二個 SQL 節點加入群組中。

New-ADGroup -Name gmsa-sql-alwayson -Description "Security group for gMSAsql computers" -GroupCategory Security -GroupScope Global

4-1 將 SQL 節點加入群組中。

Add-ADGroupMember -Identity gmsa-sql-alwayson -Members SQL2019-AG1$,SQL2019-AG2$

PS: 上述的 SQL2019-AG1$ 是第一台節點,SQL2019-AG2$ 為第二個節點。

4-2 透過下列的語法查詢目前此群組中的成員有那些。

Get-ADGroupMember -Identity gmsa-sql-alwayson

4-3 也可以透過 Active Directory Users and Computers 介面的方式進行檢示。

5. 建立 群組受控服務帳戶 (Group Managed Service Accounts)

New-ADServiceAccount -name gMSAsql -DNSHostName gMSAsql.mscaryhsu.com -PrincipalsAllowedToRetrieveManagedPassword gmsa-sql-alwayson

Get-ADServiceAccount gMSAsql -Property PasswordLastSet

PS: 上述你也可以查詢到此帳號密碼最後更新的時間

6. 設定此 群組受控服務帳戶 (Group Managed Service Accounts) 可以擁有註冊 SPN 的權限,這個非常的重要,後面我們也會確認是否在更換帳號後可以正確的註冊 SPN.  

dsacls (Get-ADServiceAccount -Identity gMSAsql).DistinguishedName /G "SELF:RPWP;servicePrincipalName"

7. 一切設定完成後,必須到各自的節點進行套用,我們先登入到第一台節點,再登入到第二個節點進行即可。

8.  啟用 Windows 的功能

8-1 檢查功能是否已啟用

PS C:\> Get-WindowsFeature AD-Domain-Services

Display Name                           Name                Install State
------------                           ----                -------------
[ ] Active Directory Domain Services   AD-Domain-Services  Available


8-2 啟用此功能

PS C:\Users\Administrator> Add-WindowsFeature AD-Domain-Services

Display Name                                            Name                       Install State
------------                                            ----                       -------------
[X] Active Directory Domain Services                    AD-Domain-Services             Installed


9.  啟用 群組受控服務帳戶 (Group Managed Service Accounts)

Install-ADServiceAccount -Identity gMSAsql
Test-ADServiceAccount -Identity gMSAsql

10. 請至另一個節點也是完成 8與9 的步驟

11. 完成上述的步驟後,就已完成 群組受控服務帳戶 (Group Managed Service Accounts) 的設定,完成設定後,請至 SQL Server Configuration Manager 更換 SQL Server 的啟動帳號,請注意千萬不要透過系統中的服務列表進行更換,否則會有問題。


12. 更換完成後,目前已是最小權限,但仍建議進行作業系統上的系統原則,有二個是一定要設定的,要不然也是會因為權限不夠,而造成問題,一個是 啟用鎖定記憶體分頁選項 (Lock pages in memory) 與 執行磁碟區維護工作(Perform volume maintenance tasks),這二個設定也是在二個節點都需要進行。



執行磁碟區維護工作(Perform volume maintenance tasks)
執行磁碟區維護工作 - Windows Security | Microsoft Learn


13. 確認上述的二個設定是否有啟用成功

13-1 透過 SQL Server Error Log

2023-11-08 15:10:34.63 Server      Using locked pages in the memory manager.

13-2 透過 DMV 查詢是否有啟用成功

SELECT sql_memory_model, sql_memory_model_desc
FROM sys.dm_os_sys_info;

沒有啟用



啟用 Lock pages in memory



14. 另外在 SQL 各個服務的部份,下列的文章也有詳細的介紹所需的權限,這樣即可達到最小化權限的部份,目前我並沒有透過下列的文章進行,確認是沒有問題的,但仍建議在相關的目錄上,尤其是 SQL Server 的主要引擎的部份仍是需要進行設定。

Configure Windows service accounts and permissions
https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/configure-windows-service-accounts-and-permissions?view=sql-server-ver16#GMSA

15. 最後我們也確認在 AlwaysOn 的部份也是一切正常,


16. 在權限的部份,網域帳號的群組,不是歸屬在 Domain Admin 中,而且也不歸屬在任何的群組中,而在 SQL Server 中,只有自動加入的電腦帳號,其中也只有 Connect 的權限而已,所以這部份絕對是最小化的權限。

2023年11月6日 星期一

啟用即時初始化檔案 (Instant file initialization) 的功能於 SQL Server 上

        即時初始化檔案 (Instant file initialization) 其實在 SQL Server 2005 就有提出,但隨著 SQL Server 版本的更新,此功能也不斷的更新與強化,所以此篇也特別介紹一下這個功能。

即時初始化檔案 (Instant file initialization) 主要說穿了,就是在建立資料庫 (Database) ,擴展空間或是還原資料庫等動作時,不進行磁碟初始化寫 zero 0 的動作,藉以加快初始化的動作,這樣一來在要求空間等動作時,可以加快申請的初始化動作,而且在 資料頁面(Data File) 的空間要求越大時,效果更是明顯,因為可以略過初始化填寫 zero 0 的動作。

通常有利也是有弊,我們在啟用這個功能時,也在深入的探討這個功能是否真的這麼強悍,但是否真的有適合不同的資料庫環境,我們分成下列的幾個方向進行討論。

1. 啟用此功能後是否會造成資料的錯寫或是錯亂等問題。

此功能持續觀察與使用已久,坦白說沒有遇過客戶回饋等問題,而且在相關的修正上,也沒有發現,所以這部份我覺得不是主要的問題。

2. 啟用後對效能上的影響,大約會有多少,是否有其他的負面影嚮。

此功能在啟用後,主要是進行相關動作時,不會針對 資料頁面(Data Page) 進行初始化寫 0 的動作,所以可以大大的加速擴展空間、建立資料庫、還原資料庫等動作,但是在負面影嚮的部份,我覺得主要是在安全性的部份,由於資料頁面沒有進一步的初始化,所以當有人透過此磁碟進行資料還原等動作時,是有可能可以查到之磁碟上原先存放的資料為何,這在有些管理上,可能是不允許的,也是有一定的風險存在的。

此功能在支援上,地端與雲端會有不同的支援程度,在雲端上,部份是沒有支援的,如 Azure 原本也是沒有支援的,但後來在 transaction log 的部份,是有 "部份" 支援的,但相對的 資料頁面(Data Page) 的部份,也是沒有支援的。

Database instant file initialization
Database instant file initialization - SQL Server | Microsoft Learn

另外在 AWS 上,很多人會透過 Amazon FSx for Windows File Server 來當作 SQL Disk 的部份,這部份也是沒有支援的,因為這個以前也有遇過客戶來討論過效能的問題,後來發現是不支援此功能,所以印像特別的深刻。

Using FSx for Windows File Server with Microsoft SQL Server
Using FSx for Windows File Server with Microsoft SQL Server - Amazon FSx for Windows File Server

說了這麼多,我們就來開始介紹如何進行啟用的方式。

在啟用的部份,你可以在一開始安裝時,在 Server Configuration 的部份,勾選 "Grant Perform Volme Maintenance Task privilege to SQL Server Database Engine Service" 的選項。


或是安裝完成後,從 SQL Server Configuration Manager -> SQL Server Service -> SQL Server(Instance name) -> Properties -> Advanced -> Instant File Initialization


另外在啟用時也請確認在作業系統層級,是否有權限進行套用,從 Local Security Policy -> Local Policies -> User Rights Assignment -> Perform volume maintenance tasks,請將你的 SQL Server 的啟動帳號加入此區的設定中即可。


設定完成後,你可以透過二個方式確認 SQL Server 是否有套用到 Instant file initialization 的功能。

1. 透過 SQL Server 的 Error Log 確認啟動時是否有套用此功能。

2023-11-03 18:02:37.12 Server      Database Instant File Initialization: enabled. For security and performance considerations see the topic 'Database Instant File Initialization' in SQL Server Books Online. This is an informational message only. No user action is required.

2. 透過 T-SQL 指令查詢是否有啟用 Instant file initialization。

select servicename, status_desc, service_account, instant_file_initialization_enabled from sys.dm_server_services



一切準備就緒就後,我們可以來透過建立資料庫的方式,來比較二者間的差異,藉以了解在啟用後之間的差異。

--啟用 Trace Flag 將建立資料庫等資訊寫入至 SQL LOG 中。
DBCC TRACEON(3004 ,3605 ,-1);
GO

CREATE DATABASE [testIFI]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'testIFI', 
  FILENAME = N'C:\tmp\testIFI.mdf' , 
  SIZE = 40GB)
 LOG ON 
( NAME = N'testIFI_log', 
  FILENAME = N'C:\tmp\testIFI_log.ldf' , 
  SIZE = 20GB)
GO


輸出比對:
2023-11-03 17:52:14.76 Server      Database Instant File Initialization: disabled.
2023-11-03 17:54:39.78 spid64      Zeroing C:\tmp\testIFI.mdf from page 0 to 5242880 (0x0 to 0xa00000000)
2023-11-03 17:54:44.13 spid64      Zeroing completed on C:\tmp\testIFI.mdf (elapsed = 4347 ms)
2023-11-03 17:55:33.57 spid64      Zeroing C:\tmp\testIFI_log.ldf from page 0 to 2621440 (0x0 to 0x500000000)
2023-11-03 17:56:25.14 spid64      Zeroing completed on C:\tmp\testIFI_log.ldf (elapsed = 51562 ms)
2023-11-03 17:56:25.23 spid64      Starting up database 'testIFI'.
2023-11-03 17:56:25.26 spid64      Parallel redo is started for database 'testIFI' with worker pool size [1].
2023-11-03 17:56:25.26 spid64      FixupLogTail(progress) zeroing 2 from 0x5000 to 0x6000.
2023-11-03 17:56:25.26 spid64      Zeroing C:\tmp\testIFI_log.ldf from page 3 to 483 (0x6000 to 0x3c6000)
2023-11-03 17:56:25.27 spid64      Zeroing completed on C:\tmp\testIFI_log.ldf (elapsed = 7 ms)
2023-11-03 17:56:25.28 spid64      Parallel redo is shutdown for database 'testIFI' with worker pool size [1].

2023-11-03 18:02:37.12 Server      Database Instant File Initialization: enabled. For security and performance considerations see the topic 'Database Instant File Initialization' in SQL Server Books Online. This is an informational message only. No user action is required.
2023-11-03 18:04:43.74 spid63      Zeroing C:\tmp\testIFI2_log.ldf from page 0 to 2621440 (0x0 to 0x500000000)
2023-11-03 18:06:14.82 spid63      Zeroing completed on C:\tmp\testIFI2_log.ldf (elapsed = 91083 ms)
2023-11-03 18:06:14.90 spid63      Starting up database 'testIFI2'.
2023-11-03 18:06:14.94 spid63      Parallel redo is started for database 'testIFI2' with worker pool size [1].
2023-11-03 18:06:14.94 spid63      FixupLogTail(progress) zeroing 2 from 0x5000 to 0x6000.
2023-11-03 18:06:14.94 spid63      Zeroing C:\tmp\testIFI2_log.ldf from page 3 to 483 (0x6000 to 0x3c6000)
2023-11-03 18:06:14.95 spid63      Zeroing completed on C:\tmp\testIFI2_log.ldf (elapsed = 8 ms)
2023-11-03 18:06:14.96 spid63      Parallel redo is shutdown for database 'testIFI2' with worker pool size [1].

從上述的結果,你就可以看到,當 Instant File Initialization 啟用時,資料頁面 (Data Page) 是完全不作初始化的動作 (zero),如同上述的說明,最後仍提醒在啟用此功能其實是真的可以大幅減少相關擴展的動作,但其相對的安全性,只能說可能要依不同的行業別在進行評估,如金融業等,當然存放資料的不同,可能也是要考慮,最後也希望此篇可以幫助到大家。

2022年4月6日 星期三

SQL Server - 如何設置單向式合併式複寫

 SQL Server - Replication 複寫是一個在很早的版本就已存在的技術,由於其特性,所以其實有許多的使用者使用,基本上四種常見的複寫上有何差異我就不在特別的介紹,因為已有許多的文章進行說明與比較,而在上一篇文章中,我介紹如何在 AWS RDS for SQL Server 與地端的 SQL Server 進行合併式複寫,這一篇我就再來進一步的介紹如果強制設定單向式的合併式複寫。

優點:

一般複寫在維護上,最怕的就是遇到衝突或是複寫過慢等問題,由於在交易式複寫 (Transactional replication) 與點對點式複寫 (Peer-to-peer replication) 的部份,一遇到衝突,絕大部份需要透過重新建立的方式進行,所以當業務上的需求只需要將資料複寫至遠端時,設定設定成單向式複寫,即可保證目的端的資料不會被變動到。

前一篇設定參考:

如何透過Merge Replication 複寫機制,同步 EC2 與 AWS RDS for SQL Server 的資料庫https://caryhsu.blogspot.com/2022/03/merge-replication-ec2-aws-rds-for-sql.html

詳細的設定方式,可能參考上述文章的介紹,但在加入表格 (Articles) 時,可以再進一步的設定即可,所以我就直接說重點的部份。

1. 先選擇好你要複寫的表格後,然後再點選右上角的 [Article Properties] -> [Properties for All Table Articles].


2. 開啟設定後,您會看到 [Synchronization direction] 的部份,預設為 Bidrectional ,這時可以開啟此設定,你會看到有三個選項。

  • Bidirectional: 雙向式復寫,這也是預設值。
  • Download to Subscriber, prohibit Subscriber changes: 只允許發行端可進行修改,而且當訂閱端進行資料變更時,會發生錯誤訊息,並且不允許進行變更,另外也不會將訂閱端的資料回寫回發行端。
  • Download to Subscriber, allow Subscriber changes: 允許發行端與訂閱端皆可進行修改,但並不會將訂閱端的資料回寫回發行端,而且發行端的數據,也會覆蓋到訂閱端。

此處我們建議可以設定第2項與第3的部份,二者的差異在於,當如果設定為 [Download to Subscriber, prohibit Subscriber changes] 時,如果你在訂閱端進行資料的修改時,就會發生下列的錯誤訊息。

錯誤訊息:
No row was updated.

The data in row 1 was not committed.
Error Source: .Net SqlClient Data Provider.
Error Message: Table '[Person].[Address]' into which you are trying to insert, update, or delete data has been marked as read-only, Only the merge process can perform these operations.



另外如果在已設定好的機器上,需要進行上述的修改時,也是一樣可以的,只是最後在修改後,需要再進行重建快照的動作後即可。


2022年3月10日 星期四

Bastion Host 防禦/堡壘主機 最佳作法於 AWS 上

 AWS 上可以建立自已的虛擬主機,也就是 EC2,但為了安全性等原因,所以通常會將 EC2 放置在私有網段 (Private Subnet),而會找一台主機放置在公開網段 (Public Subnet),這也是我們所說的 Bastion Host (防禦/堡壘主機),但這樣就沒有問題了嗎?其實還是有下列的問題。

可能遇到的問題:

1. Key Pair 的管理問題,由於 Key Pair 是以檔案的方式進行管理,所以當使用者離職後,就無法有效的管理。
2. 必須將 Bastion Host 放置於公開網段,而且需要開啟埠端口(RDP 3389/SSH 22)。
3. 無法稽核使有用者輸入過那些指令。
4. 不需要特別登入 AWS Console 即可進行連結。
5. 可以同時支援 Windows 與 Linux 的使用,這邊比較難的事,在 Session Manager 登入時只能透過文字介面與 PowerShell 的介面方式登入,但本篇我們會說明如何透過 Session Manager Port Forward 的功能達到圖型化介面 GUI 的方式進行登入。

由於目前已有許多的客戶已在透過 Systems Manager Session Manager 來當作連線的方式,所以接下來我們來說明該如何完成上述的項目,藉以達到一個遠端登入最好的管理方式。

1. 請先建立一個私有網段 (Private Subnet),也就是不要附加 Internet Gateway (IGW) 或 NAT 於 Route Table 中。

VPC with public and private subnets (NAT)
https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Scenario2.html

2. 由於在私有網段 (Private Subnet) ,所以必須建立相對應的 VPC Endpoint,請參考下列的文章,分別建立三個 VPC Endpoint。

  • ssm.region.amazonaws.com
  • ec2messages.region.amazonaws.com
  • ssmmessages.region.amazonaws.com

上述前二個是 SSM 的必要條件,而第三個是當你要使用 SSM Session Manager 時,就一定要使用。

另外由於我們想將 Session Manager 的所有活動記錄,也就是使用者所有的輸入指令都記錄下來,所以我們要將 Session activity logs 全部放置在同一個 S3 中,然後可以再透過 Amazon Athena 進行查詢,藉以找出是否有人有輸入特殊指令,如刪除檔案、查看敏感檔案等。

  • com.amazonaws.region.s3

另外由於 S3 的 endpoint 比較不同,所以最後,我們必須在 EC2 中的 Security Group 中特別設定加入一組 prefix list 這樣才可以正常的輸出 Session activity logs 到 S3 中。

Step 6: (Optional) Create a Virtual Private Cloud endpoint
https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-create-vpc.html

3. 請先針對 Systems Manager 建立一個最小權限的 IAM role,藉以後續可以附加在 EC2 Instance 中。

IAM Policy: AmazonSSMManagedInstanceCore

另外由於上述的 Policy 不包含 S3,所以也請同時加上 S3 的權限,如果你想簡單化這部份,你也可以直接使用 IAM Role [AmazonEC2RoleforSSM] 即可,但如果想要細部設定只可以使用特定的 S3 時,即可參考下列的連結。

Step 4: Create an IAM instance profile for Systems Manager
https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html

4. 上述的動作完成後,即已完成環境的設定,所以此時,請嘗試啟動一台 Windows EC2,並且在啟動的過程中,將你在步驟3建立的 IAM 給附加上。

注意,此部份你不需要開啟任何的 3389 port 或是 22 port,所以我的 inbound 是空白的,沒有新增開啟任何的規則。

5. 此時你可以先到 Systems Manager -> Fleet Manager 中確認你的主機是否已有顯示在清單中。

6. 此時你可以透過 EC2 中的 Connect -> Session Manger 進行連線,或是從 Systems Manager -> Session Manager 中進行連線,連線成功後,你會發現只有 PowerShell 的命令視窗,此時代表你已成功並且完成相關的設定。



7. 目前新功能上來說,也可以透過 Systems Manager -> Fleet Manager -> Node actions -> Connect with Remote Desktop 直接連接,但可惜這個方法目前無法使用剪貼簿導向,但可以看出在使用上已更加的方便了。


8. 接下來,我要說明如何透過 Systems Manager Session Manager 中的 Port Forwarding 的功能進行。

9. 請設定一個身份,可以執行 Session Manager 的動作,你也可以參考下列的文章。


10. 設定完成後,請完成安裝 AWS Command Line Interface (CLI) 與 Systems Manager CLI Extension,藉以可以啟動 Port Forwarding 的功能。


11. 安裝完成後,我們嘗試執行下列的指令,進行 Port Forwarding 的功能。

aws ssm start-session --target i-00e2a0ca3c861a3b5 --document-name AWS-StartPortForwardingSession --parameters '{"portNumber":["3389"], "localPortNumber":["9999"]}' --region ap-northeast-1


12. 最後,我們再透過 RDP Client 的軟體進行連線,你就會發現,可以在不開任何的 Port 的情況下,進行連線了。


13. 最後,我們要設定將所有的 Session Manager 的記錄輸出至 S3 中,所以請至 Systems Manager -> Preferences -> Edit