科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置

你好

我決定分享我的發現——思考、嘗試和錯誤的成果。
總的來說:這當然不是一個發現——對於那些參與應用統計數據處理和任何系統優化的人來說,所有這些都應該已經知道很長時間了,不一定是專門針對 DBMS 的人。
而且:是的,他們知道,他們寫了關於他們的研究的有趣文章, 例子 (更新:在評論中他們指出了一個非常有趣的項目: 奧特圖納 )
另一方面:我沒有看到 IT 專家、DBA 在網路上廣泛提及或傳播這種方法。

那麼,說到重點了。

假設我們有一個任務:建立一定的服務系統來服務某項工作。

知道這個作品:它是什麼,這個作品的品質如何衡量,衡量這個品質的標準是什麼。

我們也假設它或多或少是已知和理解的:確切地說,工作是如何在該服務系統中(或使用該服務系統)執行的。

「或多或少」-這意味著可以準備(或從某處獲取)某種工具、實用程式、服務,這些工具、實用程式、服務可以合成並應用於系統,測試負載足以滿足生產中的需要,在足夠適合生產工作的條件下。

好吧,我們假設該服務系統的一組調整參數是已知的,這些參數可用於根據系統的工作效率來配置該系統。

問題是什麼 - 對該服務系統沒有足夠完整的了解,該系統允許您熟練地配置該系統的設置以適應給定平台上的未來負載並獲得系統所需的生產力。

出色地。 情況幾乎總是如此。

你在這裡能做什麼?

嗯,首先想到的是查看該系統的文檔。 了解調整參數值的可接受範圍。 並且,例如,使用座標下降法,在測試中為系統參數選擇值。

那些。 以一組特定的配置參數值的形式為系統提供某種配置。

使用這個工具實用程式負載產生器對其應用測試負載。
並查看價值 - 響應或系統品質的度量。

第二個想法可能會得出這樣的結論:這已經是很長的時間了。

好吧,那就是:如果有很多設定參數,如果它們運行的值的範圍很大,如果每個單獨的負載測試需要很長時間才能完成,那麼:是的,這一切可能需要一個令人無法接受的時間很久。

好吧,這就是您可以理解和記住的內容。

你可以發現,在服務系統設定參數的值集中有一個向量,作為一些值的序列。

在其他條件相同的情況下(因為它不受該向量的影響),每個這樣的向量都對應於完全確定的度量值——測試負載下系統運行品質的指標。

讓我們將系統配置向量表示為 科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置哪裡 科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置; 在哪裡 科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置 — 系統配置參數的數量,這些參數有幾個。

以及與此對應的metric的值 科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置 讓我們將其表示為
科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置,那我們得到一個函數: 科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置

好吧,那麼:就我而言,一切都立即歸結為:在我的學生時代幾乎被遺忘的搜尋函數極值的演算法。

好的,但是這裡出現了一個組織和應用的問題:使用哪種演算法。

  1. 從某種意義上來說——這樣你就可以減少手動編碼。
  2. 並讓它發揮作用,即找到極值(如果有的話),好吧,至少比坐標下降更快。

第一點暗示我們需要尋找一些已經實現此類演算法的環境,並以某種形式準備在程式碼中使用。
嗯,我知道 python и cran-r

第二點意味著你需要了解演算法本身,它們是什麼,它們的要求是什麼,以及它們工作的特徵。

它們給出的可能是有用的副作用——結果,或直接來自演算法本身。

或者它們可以從演算法的結果中獲得。

很大程度取決於輸入條件。

例如,如果出於某種原因,您需要更快地獲得結果,那麼您需要考慮梯度下降演算法並選擇其中一種。

或者,如果時間不是那麼重要,您可以使用隨機最佳化方法,例如遺傳演算法。

我建議在接下來的實驗室工作中考慮這種方法的工作,選擇系統配置,使用遺傳演算法。

原來的:

  1. 讓它成為一個服務系統: oracle xe 18c
  2. 讓它服務於事務活動和目標:獲得子資料庫的最高可能吞吐量(以事務/秒為單位)。
  3. 事務處理資料的性質和工作環境可能有很大不同。
    我們同意這些事務不處理大量表格資料。
    從某種意義上說,它們不會產生比重做更多的撤消數據,並且不會處理大量的行和大型表。

這些事務會更改或多或少較大的表中的一行,並且該表上有少量索引。

在這種情況下:處理交易的子資料庫的生產率將有保留地由氧化還原資料庫的處理品質決定。

免責聲明 - 如果我們具體談論子資料庫設定。

因為,在一般情況下,由於使用者使用表格資料和/或表格模型的設計,在 SQL 會話之間可能存在事務鎖。

當然,這會對 TPS 指標產生抑製作用,並且相對於子資料庫而言,這將是一個外生因素:嗯,這就是表格模型的設計方式以及如何處理其中發生阻塞的資料。

因此,為了實驗的純度,我們會排除這個因素,以下我會具體說明如何排除。

  1. 為了明確起見,我們假設提交給資料庫的 SQL 命令 100% 都是 DML 命令。
    測試時讓使用者操作子資料庫的特性相同。
    即:skl 會話的數量、表格資料、skl 會話如何使用它們。
  2. Subd 工作於 FORCE LOGGING, ARCHIVELOG 模組。 閃回資料庫模式在子層級關閉。
  3. 重做日誌:位於單獨的檔案系統、單獨的「磁碟」上;
    資料庫的其餘實體組件:在另一個單獨的檔案系統中,在單獨的「磁碟」上:

有關物理設備的更多詳細資訊。 實驗室資料庫組件

SQL> select status||' '||name from v$controlfile;
 /db/u14/oradata/XE/control01.ctl
SQL> select GROUP#||' '||MEMBER from v$logfile;
1 /db/u02/oradata/XE/redo01_01.log
2 /db/u02/oradata/XE/redo02_01.log
SQL> select FILE_ID||' '||TABLESPACE_NAME||' '||round(BYTES/1024/1024,2)||' '||FILE_NAME as col from dba_data_files;
4 UNDOTBS1 2208 /db/u14/oradata/XE/undotbs1_01.dbf
2 SLOB 128 /db/u14/oradata/XE/slob01.dbf
7 USERS 5 /db/u14/oradata/XE/users01.dbf
1 SYSTEM 860 /db/u14/oradata/XE/system01.dbf
3 SYSAUX 550 /db/u14/oradata/XE/sysaux01.dbf
5 MONITOR 128 /db/u14/oradata/XE/monitor.dbf
SQL> !cat /proc/mounts | egrep "/db/u[0-2]"
/dev/vda1 /db/u14 ext4 rw,noatime,nodiratime,data=ordered 0 0
/dev/mapper/vgsys-ora_redo /db/u02 xfs rw,noatime,nodiratime,attr2,nobarrier,inode64,logbsize=256k,noquota 0 0

最初,在這些負載條件下,我想使用交易 subd SLOB 實用程式
它有這麼棒的功能,我引用一下作者的話:

SLOB 的核心是「SLOB 方法」。 SLOB 方法旨在測試平台
沒有應用程式爭用。 無法驅動最大的硬體效能
使用應用程式程式碼,例如,受應用程式鎖定或甚至約束的應用程式程式碼
共享 Oracle 資料庫區塊。 沒錯,共享資料時會產生開銷
在資料塊中! 但 SLOB(在其預設部署中)不受此類爭用的影響。

此聲明:對應,確實如此。
方便調節cl會話的並行度,這是關鍵 -t 啟動實用程式 runit.sh 來自 SLOB
DML 命令的百分比受到控制,包括發送到 subd 的文字訊息數量、每個文字會話、參數 UPDATE_PCT
單獨且非常方便: SLOB 本身,在載入會話之前和之後 - 準備一個 statspack 或 awr-snapshots(設定為準備的內容)。

然而,事實證明 SLOB 不支援持續時間小於 30 秒的 SQL 會話。
因此,我先編寫了自己的工農版裝載機,然後繼續運作。

為了清楚起見,讓我澄清一下載入程式的作用以及它是如何運作的。
本質上,加載器看起來像這樣:

工人代碼

function dotx()
{
local v_period="$2"
[ -z "v_period" ] && v_period="0"
source "/home/oracle/testingredotracе/config.conf"

$ORACLE_HOME/bin/sqlplus -S system/${v_system_pwd} << __EOF__
whenever sqlerror exit failure
set verify off
set echo off
set feedback off

define wnum="$1"
define period="$v_period"
set appinfo worker_&&wnum

declare
 v_upto number;
 v_key  number;
 v_tots number;
 v_cts  number;
begin
 select max(col1) into v_upto from system.testtab_&&wnum;
 SELECT (( SYSDATE - DATE '1970-01-01' ) * 86400 ) into v_cts FROM DUAL;
 v_tots := &&period + v_cts;
 while v_cts <= v_tots
 loop
  v_key:=abs(mod(dbms_random.random,v_upto));
  if v_key=0 then
   v_key:=1;
  end if;
  update system.testtab_&&wnum t
  set t.object_name=translate(dbms_random.string('a', 120), 'abcXYZ', '158249')
  where t.col1=v_key
  ;
  commit;
  SELECT (( SYSDATE - DATE '1970-01-01' ) * 86400 ) into v_cts FROM DUAL;
 end loop;
end;
/

exit
__EOF__
}
export -f dotx

Worker 是這樣啟動的:

運行工人

echo "starting test, duration: ${TEST_DURATION}" >> "$v_logfile"
for((i=1;i<="$SQLSESS_COUNT";i++))
do
 echo "sql-session: ${i}" >> "$v_logfile"
 dotx "$i" "${TEST_DURATION}" &
done
echo "waiting..." >> "$v_logfile"
wait

工人的桌子是這樣準備的:

創建表

function createtable() {
source "/home/oracle/testingredotracе/config.conf"
$ORACLE_HOME/bin/sqlplus -S system/${v_system_pwd} << __EOF__
whenever sqlerror continue
set verify off
set echo off
set feedback off

define wnum="$1"
define ts_name="slob"

begin
 execute immediate 'drop table system.testtab_&&wnum';
exception when others then null;
end;
/

create table system.testtab_&&wnum tablespace &&ts_name as
select rownum as col1, t.*
from sys.dba_objects t
where rownum<1000
;
create index testtab_&&wnum._idx on system.testtab_&&wnum (col1);
--alter table system.testtab_&&wnum nologging;
--alter index system.testtab_&&wnum._idx nologging;
exit
__EOF__
}
export -f createtable

seq 1 1 "$SQLSESS_COUNT" | xargs -n 1 -P 4 -I {} -t bash -c "createtable "{}"" | tee -a "$v_logfile"
echo "createtable done" >> "$v_logfile"

那些。 對於每個工作人員(實際上:資料庫中的一個單獨的 SQL 會話),都會建立一個單獨的表,工作人員使用該表進行工作。

這確保了工作會話之間不存在事務鎖定。
每個工人:做同樣的事情,有自己的桌子,桌子都是一樣的。
所有工人的工作時間相同。
而且,在足夠長的時間內,例如日誌切換肯定會發生,而且不只一次。
嗯,相應地,相關的成本和影響就出現了。
在我的例子中,我將工人的工作時間配置為 8 分鐘。

一段 statspack 報告描述了負載下 subd 的操作

Database    DB Id    Instance     Inst Num  Startup Time   Release     RAC
~~~~~~~~ ----------- ------------ -------- --------------- ----------- ---
          2929910313 XE                  1 07-Sep-20 23:12 18.0.0.0.0  NO

Host Name             Platform                CPUs Cores Sockets   Memory (G)
~~~~ ---------------- ---------------------- ----- ----- ------- ------------
     billing.izhevsk1 Linux x86 64-bit           2     2       1         15.6

Snapshot       Snap Id     Snap Time      Sessions Curs/Sess Comment
~~~~~~~~    ---------- ------------------ -------- --------- ------------------
Begin Snap:       1630 07-Sep-20 23:12:27       55        .7
  End Snap:       1631 07-Sep-20 23:20:29       62        .6
   Elapsed:       8.03 (mins) Av Act Sess:       8.4
   DB time:      67.31 (mins)      DB CPU:      15.01 (mins)

Cache Sizes            Begin        End
~~~~~~~~~~~       ---------- ----------
    Buffer Cache:     1,392M              Std Block Size:         8K
     Shared Pool:       288M                  Log Buffer:   103,424K

Load Profile              Per Second    Per Transaction    Per Exec    Per Call
~~~~~~~~~~~~      ------------------  ----------------- ----------- -----------
      DB time(s):                8.4                0.0        0.00        0.20
       DB CPU(s):                1.9                0.0        0.00        0.04
       Redo size:        7,685,765.6              978.4
   Logical reads:           60,447.0                7.7
   Block changes:           47,167.3                6.0
  Physical reads:                8.3                0.0
 Physical writes:              253.4                0.0
      User calls:               42.6                0.0
          Parses:               23.2                0.0
     Hard parses:                1.2                0.0
W/A MB processed:                1.0                0.0
          Logons:                0.5                0.0
        Executes:           15,756.5                2.0
       Rollbacks:                0.0                0.0
    Transactions:            7,855.1

回到實驗室工作。
在其他條件相同的情況下,我們將改變實驗室子資料庫的以下參數的值:

  1. 資料庫日誌組的大小。 值範圍:[32, 1024] MB;
  2. 資料庫中日記組的數量。 取值範圍:[2,32];
  3. log_archive_max_processes 取值範圍:[1,8];
  4. commit_logging 允許兩個值: batch|immediate;
  5. commit_wait 允許兩個值: wait|nowait;
  6. log_buffer 值範圍:[2,128] MB。
  7. log_checkpoint_timeout 值範圍:[60,1200]秒
  8. db_writer_processes 取值範圍:[1,4]
  9. undo_retention 值範圍:[30;300]秒
  10. transactions_per_rollback_segment 取值範圍:[1,8]
  11. disk_asynch_io 允許兩個值: true|false;
  12. filesystemio_options 允許使用以下值: none|setall|directIO|asynch;
  13. db_block_checking 允許使用以下值: OFF|LOW|MEDIUM|FULL;
  14. db_block_checksum 允許使用以下值: OFF|TYPICAL|FULL;

具有維護 Oracle 資料庫經驗的人當然已經可以從指定的參數及其可接受的值中說出應該設定什麼以及應該設定什麼值,以便獲得資料庫更高的生產力來處理由應用程式程式碼,在上面。

不過。

實驗室工作的目的是表明優化演算法本身將相對快速地為我們澄清這一點。

對於我們來說,剩下的就是透過可自訂的系統查看文檔,足以找出要更改哪些參數以及在什麼範圍內更改。
並且:編寫將用於與所選優化演算法的自訂系統一起工作的程式碼。

那麼,現在關於代碼。
我在上面談到 cran-r,即:自訂系統的所有操作都以 R 腳本的形式編排。

實際任務、分析、依度量值選擇、系統狀態向量:這是一個套件 GA (文件)
在這種情況下,該包不是很合適,因為它期望向量(染色體,如果就包而言)以帶有小數部分的數字字串的形式指定。

而我的向量,從設定參數的值來看:這些是 14 個數量 - 整數和字串值。

當然,透過將一些特定數字分配給字串值可以輕鬆避免該問題。

因此,最終 R 腳本的主要部分如下所示:

呼叫 GA::ga

cat( "", file=v_logfile, sep="n", append=F)

pSize = 10
elitism_value=1
pmutation_coef=0.8
pcrossover_coef=0.1
iterations=50

gam=GA::ga(type="real-valued", fitness=evaluate,
lower=c(32,2, 1,1,1,2,60,1,30,1,0,0, 0,0), upper=c(1024,32, 8,10,10,128,800,4,300,8,10,40, 40,30),
popSize=pSize,
pcrossover = pcrossover_coef,
pmutation = pmutation_coef,
maxiter=iterations,
run=4,
keepBest=T)
cat( "GA-session is done" , file=v_logfile, sep="n", append=T)
gam@solution

在這裡,在幫助下 lower и upper 子程序屬性 ga 本質上,指定搜尋空間的一個區域,在該區域內將搜尋一個或多個向量,以獲得適應度函數的最大值。

ga 子程式執行最大化適應度函數的搜尋。

那麼,事實證明,在這種情況下,適應度函數必須將向量理解為 subd 某些參數的一組值,並從 subd 接收度量。

也就是說:在給定的子程序設定和子程序上給定的負載下有多少:子程序每秒處理交易。

也就是說,展開時,適應度函數內部必須執行以下多步驟:

  1. 處理數字的輸入向量 - 將其轉換為子資料參數的值。
  2. 嘗試建立給定數量、給定大小的重做群組。 而且,這種嘗試可能會失敗。
    為了實驗的純粹性,已經在 subd 中存在一定數量和一定規模的雜誌組 - d.b. 已刪除。
  3. 如果上一點成功:向資料庫指定配置參數的值(同樣:可能會失敗)
  4. 如果上一個步驟成功:停止subd,啟動subd,使新指定的參數值生效。 (再次強調:可能有問題)
  5. 如果上一步成功:執行負載測試。 從 subd 取得指標。
  6. 將 subd 返回其原始狀態,即刪除額外的日誌組,使原始子資料庫配置恢復工作。

健身功能代碼

evaluate=function(p_par) {
v_module="evaluate"
v_metric=0
opn=NULL
opn$rg_size=round(p_par[1],digit=0)
opn$rg_count=round(p_par[2],digit=0)
opn$log_archive_max_processes=round(p_par[3],digit=0)
opn$commit_logging="BATCH"
if ( round(p_par[4],digit=0) > 5 ) {
 opn$commit_logging="IMMEDIATE"
}
opn$commit_logging=paste("'", opn$commit_logging, "'",sep="")

opn$commit_wait="WAIT"
if ( round(p_par[5],digit=0) > 5 ) {
 opn$commit_wait="NOWAIT"
}
opn$commit_wait=paste("'", opn$commit_wait, "'",sep="")

opn$log_buffer=paste(round(p_par[6],digit=0),"m",sep="")
opn$log_checkpoint_timeout=round(p_par[7],digit=0)
opn$db_writer_processes=round(p_par[8],digit=0)
opn$undo_retention=round(p_par[9],digit=0)
opn$transactions_per_rollback_segment=round(p_par[10],digit=0)
opn$disk_asynch_io="true"
if ( round(p_par[11],digit=0) > 5 ) {
 opn$disk_asynch_io="false"
} 

opn$filesystemio_options="none"
if ( round(p_par[12],digit=0) > 10 && round(p_par[12],digit=0) <= 20 ) {
 opn$filesystemio_options="setall"
}
if ( round(p_par[12],digit=0) > 20 && round(p_par[12],digit=0) <= 30 ) {
 opn$filesystemio_options="directIO"
}
if ( round(p_par[12],digit=0) > 30 ) {
 opn$filesystemio_options="asynch"
}

opn$db_block_checking="OFF"
if ( round(p_par[13],digit=0) > 10 && round(p_par[13],digit=0) <= 20 ) {
 opn$db_block_checking="LOW"
}
if ( round(p_par[13],digit=0) > 20 && round(p_par[13],digit=0) <= 30 ) {
 opn$db_block_checking="MEDIUM"
}
if ( round(p_par[13],digit=0) > 30 ) {
 opn$db_block_checking="FULL"
}

opn$db_block_checksum="OFF"
if ( round(p_par[14],digit=0) > 10 && round(p_par[14],digit=0) <= 20 ) {
 opn$db_block_checksum="TYPICAL"
}
if ( round(p_par[14],digit=0) > 20 ) {
 opn$db_block_checksum="FULL"
}

v_vector=paste(round(p_par[1],digit=0),round(p_par[2],digit=0),round(p_par[3],digit=0),round(p_par[4],digit=0),round(p_par[5],digit=0),round(p_par[6],digit=0),round(p_par[7],digit=0),round(p_par[8],digit=0),round(p_par[9],digit=0),round(p_par[10],digit=0),round(p_par[11],digit=0),round(p_par[12],digit=0),round(p_par[13],digit=0),round(p_par[14],digit=0),sep=";")
cat( paste(v_module," try to evaluate vector: ", v_vector,sep="") , file=v_logfile, sep="n", append=T)

rc=make_additional_rgroups(opn)
if ( rc!=0 ) {
 cat( paste(v_module,"make_additional_rgroups failed",sep="") , file=v_logfile, sep="n", append=T)
 return (0)
}

v_rc=0
rc=set_db_parameter("log_archive_max_processes", opn$log_archive_max_processes)
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("commit_logging", opn$commit_logging )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("commit_wait", opn$commit_wait )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("log_buffer", opn$log_buffer )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("log_checkpoint_timeout", opn$log_checkpoint_timeout )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("db_writer_processes", opn$db_writer_processes )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("undo_retention", opn$undo_retention )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("transactions_per_rollback_segment", opn$transactions_per_rollback_segment )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("disk_asynch_io", opn$disk_asynch_io )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("filesystemio_options", opn$filesystemio_options )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("db_block_checking", opn$db_block_checking )
if ( rc != 0 ) {  v_rc=1 }
rc=set_db_parameter("db_block_checksum", opn$db_block_checksum )
if ( rc != 0 ) {  v_rc=1 }

if ( rc!=0 ) {
 cat( paste(v_module," can not startup db with that vector of settings",sep="") , file=v_logfile, sep="n", append=T)
 rc=stop_db("immediate")
 rc=create_spfile()
 rc=start_db("")
 rc=remove_additional_rgroups(opn)
 return (0)
}

rc=stop_db("immediate")
rc=start_db("")
if ( rc!=0 ) {
 cat( paste(v_module," can not startup db with that vector of settings",sep="") , file=v_logfile, sep="n", append=T)
 rc=stop_db("abort")
 rc=create_spfile()
 rc=start_db("")
 rc=remove_additional_rgroups(opn)
 return (0)
}

rc=run_test()
v_metric=getmetric()

rc=stop_db("immediate")
rc=create_spfile()
rc=start_db("")
rc=remove_additional_rgroups(opn)

cat( paste("result: ",v_metric," ",v_vector,sep="") , file=v_logfile, sep="n", append=T)
return (v_metric)
}

那。 所有工作:在適應度函數中執行。

ga 子程式處理向量,或更準確地說,處理染色體。
其中,對我們來說最重要的是選擇具有適應度函數產生較大值的基因的染色體。

這本質上是在N維搜尋空間中使用向量搜尋最優染色體組的過程。

非常清楚、詳細 解釋,以 R 程式碼為例,遺傳演算法的工作。

我想分別說明兩個技術點。

來自函數的輔助調用 evaluate,例如stop-start,設定subd參數的值,都是根據 cran-r 功能 system2

借助它: 呼叫一些 bash 腳本或命令。

例如:

設定資料庫參數

set_db_parameter=function(p1, p2) {
v_module="set_db_parameter"
v_cmd="/home/oracle/testingredotracе/set_db_parameter.sh"
v_args=paste(p1," ",p2,sep="")

x=system2(v_cmd, args=v_args, stdout=T, stderr=T, wait=T)
if ( length(attributes(x)) > 0 ) {
 cat(paste(v_module," failed with: ",attributes(x)$status," ",v_cmd," ",v_args,sep=""), file=v_logfile, sep="n", append=T)
 return (attributes(x)$status)
}
else {
 cat(paste(v_module," ok: ",v_cmd," ",v_args,sep=""), file=v_logfile, sep="n", append=T)
 return (0)
}
}

第二個點是線, evaluate 函數,將特定的度量值及其對應的調整向量儲存到日誌檔案中:

cat( paste("result: ",v_metric," ",v_vector,sep="") , file=v_logfile, sep="n", append=T)

這很重要,因為從該資料陣列中,可以獲得關於調整向量的哪些分量對度量值具有更大或更小的影響的附加資訊。

即:可以進行屬性重要性分析。

那麼會發生什麼事呢?

以圖表形式,如果按公制升序對測試進行排序,則圖片如下:

科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置

指標極值對應的一些數據:
科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置
在這裡,在帶有結果的螢幕截圖中,我將澄清:調整向量的值是根據適應度函數代碼給出的,而不是根據參數/參數值範圍的數量列表給出的,這是用公式表示的上面的文字。

出色地。 是多還是少,~8 tps:一個單獨的問題。
在實驗室工作的框架內,這個數字並不重要,重要的是動態,這個數值如何改變。

這裡的動態很好。
顯然,至少有一個因素顯著影響度量值,即 ga 演算法,對染色體向量進行排序:覆蓋。
從曲線值相當活躍的動態來看,至少還有一個因素雖然小得多,但也有影響。

這就是你需要的地方 attribute-importance 分析以了解哪些屬性(在本例中是調整向量的組成部分)以及它們對測量值的影響程度。
並從這些資訊:了解哪些因素受到重要屬性變化的影響。

運行 attribute-importance 可能以不同的方式。

出於這些目的,我喜歡該演算法 randomForest 同名的 R 包(文件)
randomForest據我了解他的工作總體情況以及他評估屬性重要性的方法,建立了響應變數對屬性的依賴關係的特定模型。

在我們的例子中,響應變數是在負載測試中從資料庫取得的指標: tps;
屬性是調整向量的組成部分。

所以這裡是 randomForest 用兩個數字評估每個模型屬性的重要性: %IncMSE — 模型中該屬性的存在/不存在如何改變該模型的 MSE 質量(均方誤差);

IncNodePurity 是一個數字,它反映了基於​​此屬性的值,可以將具有觀察結果的數據集劃分得有多好,以便在一部分中存在具有被解釋的度量值的數據,而在另一部分中具有被解釋的度量值度量的另一個值。
嗯,那就是:這在多大程度上是一個分類屬性(我在RandomForest上看到了最清晰的俄語解釋 這裡).

用於處理具有負載測試結果的資料集的工農 R 代碼:

x=NULL
v_data_file=paste('/tmp/data1.dat',sep="")
x=read.table(v_data_file, header = TRUE, sep = ";", dec=",", quote = ""'", stringsAsFactors=FALSE)
colnames(x)=c('metric','rgsize','rgcount','lamp','cmtl','cmtw','lgbffr','lct','dbwrp','undo_retention','tprs','disk_async_io','filesystemio_options','db_block_checking','db_block_checksum')

idxTrain=sample(nrow(x),as.integer(nrow(x)*0.7))
idxNotTrain=which(! 1:nrow(x) %in% idxTrain )
TrainDS=x[idxTrain,]
ValidateDS=x[idxNotTrain,]

library(randomForest)
#mtry=as.integer( sqrt(dim(x)[2]-1) )
rf=randomForest(metric ~ ., data=TrainDS, ntree=40, mtry=3, replace=T, nodesize=2, importance=T, do.trace=10, localImp=F)
ValidateDS$predicted=predict(rf, newdata=ValidateDS[,colnames(ValidateDS)!="metric"], type="response")
sum((ValidateDS$metric-ValidateDS$predicted)^2)
rf$importance

您可以直接用手選擇演算法的超參數,並專注於模型的質量,選擇更準確地滿足驗證資料集預測的模型。
您可以為此工作編寫某種函數(順便說一下,再次使用某種最佳化演算法)。

您可以使用 R 套件 caret,不是重點。

因此,在這種情況下,可以得到以下結果來評估屬性的重要性:

科學的 poke 方法,或如何使用基準和優化算法選擇 subd 配置

出色地。 因此,我們可以開始全局反思:

  1. 事實證明,在這些測試條件下,最重要的是參數 commit_wait
    從技術上講,它指定了將redo資料從subdb日誌緩衝區寫入目前日誌組的io操作的執行模式:同步或非同步。
    nowait 這導致 tps 指標的值幾乎垂直地倍增:這是在重做組中包含非同步 io 模式。
    另一個問題是是否應該在食品資料庫中執行此操作。 在這裡我只想說:這是一個重要因素。
  2. subd 的日誌緩衝區大小是一個重要因素,這是合乎邏輯的。
    日誌緩衝區的大小越小,其緩衝容量越小,其溢出和/或無法在其中分配空閒區域用於一部分新的氧化還原資料的情況就越頻繁。
    這意味著:與在日誌緩衝區中分配空間和/或將重做資料從日誌緩衝區轉儲到重做群組相關的延遲。
    當然,這些延遲應該而且確實會影響資料庫的交易吞吐量。
  3. 參數 db_block_checksum:嗯,總的來說,很明顯 - 事務處理會導致子資料庫的緩衝區高速緩存中形成 darty 區塊。
    其中,當啟用檢查資料區塊校驗和時,資料庫必須處理 - 從資料區塊主體計算這些校驗和,用資料區塊標頭中寫入的內容檢查它們:匹配/不匹配。
    同樣,這樣的工作不能不延遲資料處理,因此,參數和設定該參數的機制變得非常重要。
    這就是為什麼供應商在該參數的文檔中為其(參數)提供了不同的值,並指出是的,會產生影響,但是,您可以選擇不同的值,最高可達“關閉”和不同的影響。

好吧,一個全球性的結論。

總的來說,這種方法非常有效。

他非常允許自己,在某個業務系統的負載測試的早期階段,為了選擇其(系統)針對負載的最佳配置,而不是過度鑽研為負載設定係統的細節。

但它並沒有完全排除它——至少在理解的層面上:系統必須了解「調節旋鈕」以及這些旋鈕的允許旋轉範圍。

此方法可以相對快速地找到最佳系統配置。
並且根據測試結果,可以獲得有關係統性能指標與系統設定參數值之間關係性質的資訊。

當然,這應該有助於對系統及其操作(至少在給定負載下)的這種非常深入的理解的出現。

實際上,這是理解定制系統的成本與準備系統測試的成本的交換。

我想單獨指出:在這種方法中,系統測試對其商業運行中的運行條件的充分程度至關重要。

感謝您的關注和時間。

來源: www.habr.com

添加評論