Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare

Alo

Am decis să împărtășesc descoperirea mea - rodul gândirii, încercării și erorii.
În general: aceasta nu este o descoperire, desigur - toate acestea ar fi trebuit să fie cunoscute de multă vreme, celor care sunt implicați în prelucrarea aplicată a datelor statistice și optimizarea oricăror sisteme, nu neapărat în mod specific SGBD.
Și: da, știu, scriu articole interesante despre cercetările lor, exemplu (UPD.: în comentarii au subliniat un proiect foarte interesant: ottertune )
Pe de altă parte: de la îndemână, nu văd nicio mențiune sau difuzare pe scară largă a acestei abordări pe internet în rândul specialiștilor IT, DBA.

Deci, la obiect.

Să presupunem că avem o sarcină: să instalăm un anumit sistem de service pentru a deservi un fel de muncă.

Se știe despre această lucrare: ce este, cum se măsoară calitatea acestei lucrări și care este criteriul de măsurare a acestei calități.

Să presupunem, de asemenea, că este mai mult sau mai puțin cunoscut și înțeles: exact cum se lucrează în (sau cu) acest sistem de servicii.

„Mai mult sau mai puțin” - aceasta înseamnă că este posibil să pregătiți (sau să-l obțineți de undeva) un anumit instrument, utilitate, serviciu care poate fi sintetizat și aplicat sistemului cu o sarcină de testare suficient de adecvată pentru ceea ce va fi în producție, in conditii suficient de adecvate pentru munca in productie .

Ei bine, să presupunem că este cunoscut un set de parametri de ajustare pentru acest sistem de servicii, care poate fi utilizat pentru a configura acest sistem în ceea ce privește productivitatea muncii sale.

Și care este problema - nu există o înțelegere suficient de completă a acestui sistem de servicii, una care vă permite să configurați în mod expert setările acestui sistem pentru încărcarea viitoare pe o anumită platformă și să obțineți productivitatea necesară a sistemului.

Bine. Acesta este aproape întotdeauna cazul.

Ce poți face aici?

Ei bine, primul lucru care îmi vine în minte este să te uiți la documentația pentru acest sistem. Înțelegeți care sunt intervalele acceptabile pentru valorile parametrilor de ajustare. Și, de exemplu, folosind metoda de coborâre a coordonatelor, selectați valorile pentru parametrii sistemului în teste.

Acestea. dați sistemului un fel de configurație, sub forma unui set specific de valori pentru parametrii săi de configurare.

Aplicați-i o sarcină de testare, folosind chiar acest instrument-util, generator de încărcare.
Și uită-te la valoarea - răspunsul sau o măsură a calității sistemului.

Al doilea gând poate fi concluzia că aceasta este o perioadă foarte lungă.

Ei bine, adică: dacă există o mulțime de parametri de setare, dacă intervalele de valori ale acestora rulate sunt mari, dacă fiecare test individual de sarcină durează mult timp, atunci: da, toate acestea pot dura inacceptabil. perioadă lungă de timp.

Ei bine, iată ce puteți înțelege și vă amintiți.

Puteți afla că în setul de valori ale parametrilor setărilor sistemului de service există un vector, ca o secvență a unor valori.

Fiecare astfel de vector, celelalte lucruri fiind egale (în sensul că nu este afectat de acest vector), corespunde unei valori complet definite a metricii - un indicator al calității funcționării sistemului sub o sarcină de testare.

Ie

Să notăm vectorul de configurare a sistemului ca Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizareUnde Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare; Unde Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare — numărul de parametri de configurare a sistemului, câți dintre acești parametri există.

Și valoarea metricii corespunzătoare acesteia Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare să o notăm ca
Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare, atunci obținem o funcție: Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare

Ei bine, atunci: totul se reduce imediat la, în cazul meu: aproape uitat din perioada studenției, algoritmi de căutare a extremului unei funcții.

Bine, dar aici apare o întrebare organizațională și aplicată: ce algoritm să folosești.

  1. În sensul - astfel încât să puteți codifica mai puțin manual.
  2. Și pentru ca acesta să funcționeze, i.e. a găsit extremul (dacă există unul), ei bine, cel puțin mai rapid decât coborârea coordonată.

Primul punct sugerează că trebuie să ne uităm către unele medii în care astfel de algoritmi au fost deja implementați și sunt, într-o anumită formă, gata de utilizare în cod.
Ei bine, știu python и cran-r

Al doilea punct înseamnă că trebuie să citiți despre algoritmii înșiși, ce sunt aceștia, care sunt cerințele lor și caracteristicile muncii lor.

Și ceea ce dau pot fi efecte secundare utile - rezultate sau direct din algoritmul însuși.

Sau pot fi obținute din rezultatele algoritmului.

Multe depind de condițiile de intrare.

De exemplu, dacă, dintr-un motiv oarecare, trebuie să obțineți un rezultat mai rapid, ei bine, trebuie să vă uitați la algoritmii de coborâre a gradientului și să alegeți unul dintre ei.

Sau, dacă timpul nu este atât de important, puteți, de exemplu, să utilizați metode de optimizare stocastică, cum ar fi un algoritm genetic.

Îmi propun să luăm în considerare munca acestei abordări, selectând configurația sistemului, folosind un algoritm genetic, în următoarea, ca să spunem așa: lucru de laborator.

Iniţială:

  1. Să fie, ca sistem de servicii: oracle xe 18c
  2. Lăsați-l să servească activității tranzacționale și obiectivului: obținerea celui mai mare debit posibil al subbazei de date, în tranzacții/sec.
  3. Tranzacțiile pot fi foarte diferite în ceea ce privește natura lucrului cu date și contextul de lucru.
    Să fim de acord că acestea sunt tranzacții care nu procesează o cantitate mare de date tabelare.
    În sensul că nu generează mai multe date undo decât redo și nu procesează procente mari de rânduri și tabele mari.

Acestea sunt tranzacții care modifică un rând într-un tabel mai mult sau mai puțin mare, cu un număr mic de indici pe acest tabel.

In aceasta situatie: productivitatea subbazei de date pentru prelucrarea tranzactiilor va fi determinata, cu rezerva, de calitatea prelucrarii de catre baza de date redox.

Disclaimer - dacă vorbim în mod special despre setările subdb.

Pentru că, în cazul general, pot exista, de exemplu, blocări tranzacționale între sesiunile SQL, datorită proiectării lucrului utilizatorului cu date tabulare și/sau model tabular.

Ceea ce, bineînțeles, va avea un efect deprimant asupra metricii TPS și acesta va fi un factor exogen, în raport cu subbaza de date: ei bine, așa a fost conceput modelul tabelar și lucrul cu datele din acesta ca să apară blocaje.

Prin urmare, pentru puritatea experimentului, vom exclude acest factor, iar mai jos voi clarifica exact cum.

  1. Să presupunem, pentru certitudine, că 100% din comenzile SQL trimise în baza de date sunt comenzi DML.
    Lăsați ca caracteristicile lucrului utilizatorului cu subbaza de date să fie aceleași în teste.
    Și anume: numărul de sesiuni skl, datele tabelare, cum funcționează sesiunile skl cu acestea.
  2. Subd funcționează în FORCE LOGGING, ARCHIVELOG moduri. Modul flashback-bază de date este dezactivat, la nivel subd.
  3. Redo log-uri: situate într-un sistem de fișiere separat, pe un „disc” separat;
    Restul componentei fizice a bazei de date: într-un alt sistem de fișiere separat, pe un „disc” separat:

Mai multe detalii despre dispozitivul fizic. componentele bazei de date de laborator

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

Inițial, în aceste condiții de încărcare, am vrut să folosesc tranzacția subd SLOB-utilitate
Are o caracteristică atât de minunată, îl voi cita pe autor:

În centrul SLOB se află „metoda SLOB”. Metoda SLOB are ca scop testarea platformelor
fără contestație de aplicare. Nu se poate conduce performanța hardware maximă
folosind codul aplicației care este, de exemplu, legat de blocarea aplicației sau chiar
partajarea blocurilor Oracle Database. Așa este, există o suprasarcină la partajarea datelor
în blocuri de date! Însă SLOB – în implementarea sa implicită – este imun la o astfel de dispută.

Această declarație: corespunde, este.
Este convenabil să reglați gradul de paralelism al sesiunilor cl, aceasta este cheia -t lansați utilitarul runit.sh de la SLOB
Procentul comenzilor DML este reglementat, în numărul de mesaje text care sunt trimise către subd, fiecare sesiune de text, parametru UPDATE_PCT
Separat și foarte convenabil: SLOB în sine, înainte și după sesiunea de încărcare - pregătește un pachet de statistici sau instantanee awr (ce este setat să fie pregătit).

Cu toate acestea, s-a dovedit că SLOB nu acceptă sesiuni SQL cu o durată mai mică de 30 de secunde.
Prin urmare, mi-am codificat mai întâi propria mea versiune, muncitor-țărănească, a încărcătorului, apoi a rămas în funcțiune.

Permiteți-mi să clarific ce face încărcătorul și cum o face, pentru claritate.
În esență, încărcătorul arată astfel:

Cod muncitor

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

Muncitorii sunt lansati astfel:

Muncitori care conduc

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

Și mesele pentru muncitori sunt pregătite astfel:

Crearea de tabele

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"

Acestea. Pentru fiecare lucrător (practic: o sesiune SQL separată în DB) este creat un tabel separat, cu care lucrează lucrătorul.

Acest lucru asigură absența blocărilor tranzacționale între sesiunile lucrătorilor.
Fiecare muncitor: face același lucru, cu masa lui, mesele sunt toate la fel.
Toți lucrătorii lucrează pentru aceeași perioadă de timp.
Mai mult decât atât, pentru un timp suficient de lung, astfel încât, de exemplu, o schimbare a jurnalului ar avea loc cu siguranță și de mai multe ori.
Ei bine, în consecință, au apărut costuri și efecte asociate.
În cazul meu, am configurat durata muncii muncitorilor la 8 minute.

O bucată dintr-un raport de statspack care descrie funcționarea subd-ului sub încărcare

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

Revenind la munca de laborator.
Vom varia, în egală măsură, valorile următorilor parametri ai subbazei de date de laborator:

  1. Dimensiunea grupurilor de jurnal ale bazei de date. interval de valori: [32, 1024] MB;
  2. Numărul de grupuri de jurnal din baza de date. interval de valori: [2,32];
  3. log_archive_max_processes interval de valori: [1,8];
  4. commit_logging sunt permise doua valori: batch|immediate;
  5. commit_wait sunt permise doua valori: wait|nowait;
  6. log_buffer interval de valori: [2,128] MB.
  7. log_checkpoint_timeout interval de valori: [60,1200] secunde
  8. db_writer_processes interval de valori: [1,4]
  9. undo_retention interval de valori: [30;300] secunde
  10. transactions_per_rollback_segment interval de valori: [1,8]
  11. disk_asynch_io sunt permise doua valori: true|false;
  12. filesystemio_options sunt permise următoarele valori: none|setall|directIO|asynch;
  13. db_block_checking sunt permise următoarele valori: OFF|LOW|MEDIUM|FULL;
  14. db_block_checksum sunt permise următoarele valori: OFF|TYPICAL|FULL;

O persoană cu experiență în întreținerea bazelor de date Oracle poate spune deja ce și la ce valori ar trebui setate, din parametrii specificați și valorile acceptabile ale acestora, pentru a obține o productivitate mai mare a bazei de date pentru lucrul cu datele care este indicat de codul aplicației, aici mai sus.

Dar.

Scopul muncii de laborator este să arate că algoritmul de optimizare în sine ne va clarifica acest lucru relativ rapid.

Pentru noi, tot ce rămâne este să ne uităm în document, prin sistemul personalizabil, doar cât să aflăm ce parametri trebuie modificați și în ce intervale.
Și, de asemenea: codificați codul care va fi folosit pentru a lucra cu sistemul personalizat al algoritmului de optimizare selectat.

Deci, acum despre cod.
Am vorbit mai sus despre cran-r, adică: toate manipulările cu sistemul personalizat sunt orchestrate sub forma unui script R.

Sarcina reală, analiza, selecția după valoarea metrică, vectorii de stare a sistemului: acesta este un pachet GA (documentație)
Pachetul, în acest caz, nu este foarte potrivit, în sensul că se așteaptă ca vectorii (cromozomii, dacă în ceea ce privește pachetul) să fie specificați sub formă de șiruri de numere cu o parte fracționară.

Și vectorul meu, din valorile parametrilor de setare: acestea sunt 14 cantități - numere întregi și valori de șir.

Problema, desigur, este ușor de evitat prin atribuirea unor numere specifice valorilor șirurilor.

Astfel, în cele din urmă, piesa principală a scriptului R arată astfel:

Sună 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

Aici, cu ajutorul lower и upper atributele subrutinei ga în esență, este specificată o zonă a spațiului de căutare, în cadrul căreia se va efectua o căutare pentru un astfel de vector (sau vectori) pentru care se va obține valoarea maximă a funcției de fitness.

Subrutina ga efectuează o căutare maximizând funcția de fitness.

Ei bine, atunci, se dovedește că, în acest caz, este necesar ca funcția de fitness, înțelegând vectorul ca un set de valori pentru anumiți parametri ai subd, să primească o metrică de la subd.

Adică: câte, cu o anumită configurație subd și o încărcare dată pe subd: subd procesează tranzacții pe secundă.

Adică, la desfășurare, în cadrul funcției de fitness trebuie efectuate următorii pași multipli:

  1. Procesarea vectorului de intrare al numerelor - conversia acestuia în valori pentru parametrii de subdate.
  2. O încercare de a crea un număr dat de grupuri de refacere de o dimensiune dată. În plus, încercarea poate fi eșuată.
    Grupuri de revistă care existau deja în subd, într-o oarecare cantitate și de o oarecare mărime, pentru puritatea experimentului - d.b. șters.
  3. Dacă punctul anterior are succes: specificarea valorilor parametrilor de configurare în baza de date (din nou: poate exista un eșec)
  4. Dacă pasul anterior are succes: oprirea subd-ului, pornirea subd-ului astfel încât noile valori ale parametrilor specificate să aibă efect. (din nou: poate exista o eroare)
  5. Dacă pasul anterior are succes: efectuați un test de încărcare. obține valori de la subd.
  6. Readuceți subd-ul la starea inițială, de ex. ștergeți grupuri de jurnal suplimentare, reveniți la funcționarea configurației inițiale a subbasei de date.

Codul funcției de fitness

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)
}

Acea. toate lucrările: efectuate în funcția de fitness.

Subrutina ga procesează vectori sau, mai corect, cromozomii.
În care, ceea ce este cel mai important pentru noi este selecția cromozomilor cu gene pentru care funcția de fitness produce valori mari.

Acesta, în esență, este procesul de căutare a setului optim de cromozomi folosind un vector într-un spațiu de căutare N-dimensional.

Foarte clar, detaliat explicație, cu exemple de cod R, lucrul unui algoritm genetic.

Aș dori să notez separat două puncte tehnice.

Apeluri auxiliare din funcție evaluate, de exemplu, stop-start, setarea valorii parametrului subd, sunt efectuate pe baza cran-r funcții system2

Cu ajutorul căruia: este apelat un script sau o comandă bash.

De exemplu:

set_db_parameter

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)
}
}

Al doilea punct este linia, evaluate funcții, cu salvarea unei anumite valori metrice și a vectorului său de reglare corespunzător într-un fișier jurnal:

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

Acest lucru este important, deoarece din această matrice de date, va fi posibil să se obțină informații suplimentare despre care dintre componentele vectorului de reglare are un efect mai mare sau mai mic asupra valorii metrice.

Adică: va fi posibilă efectuarea analizei atribut-importamce.

Deci ce se poate întâmpla?

Sub formă de grafic, dacă ordonați testele în ordine crescătoare metrică, imaginea este următoarea:

Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare

Câteva date corespunzătoare valorilor extreme ale metricii:
Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare
Aici, în captura de ecran cu rezultate, voi clarifica: valorile vectorului de reglare sunt date în termeni de codul funcției de fitness, nu în termeni de lista numerică a parametrilor/intervalele de valori ale parametrilor, care a fost formulată mai sus în text.

Bine. Este mult sau puțin, ~8 mii tps: o întrebare separată.
În cadrul lucrărilor de laborator, această cifră nu este importantă, ceea ce este important este dinamica, cum se schimbă această valoare.

Dinamica aici este bună.
Este evident că cel puțin un factor influențează semnificativ valoarea metricii, algoritmul ga, sortarea prin vectorii cromozomi: acoperit.
Judecând după dinamica destul de viguroasă a valorilor curbei, mai există cel puțin un factor care, deși semnificativ mai mic, are o influență.

Aici ai nevoie attribute-importance analiza pentru a înțelege ce atribute (bine, în acest caz, componente ale vectorului de reglare) și cât de mult influențează ele valoarea metrică.
Și din aceste informații: înțelegeți ce factori au fost afectați de modificările atributelor semnificative.

A executa attribute-importance posibil în moduri diferite.

În aceste scopuri, îmi place algoritmul randomForest pachet R cu același nume (documentație)
randomForest, după cum înțeleg munca lui în general și abordarea sa de a evalua importanța atributelor în special, construiește un anumit model al dependenței variabilei răspuns de atribute.

În cazul nostru, variabila răspuns este o metrică obținută din baza de date în testele de încărcare: tps;
Și atributele sunt componente ale vectorului de reglare.

Deci, aici randomForest evaluează importanța fiecărui atribut de model cu două numere: %IncMSE — cum prezența/absența acestui atribut într-un model modifică calitatea MSE a acestui model (Mean Squared Error);

Și IncNodePurity este un număr care reflectă cât de bine, pe baza valorilor acestui atribut, poate fi împărțit un set de date cu observații, astfel încât într-o parte să fie date cu o valoare a metricii explicate, iar în cealaltă cu o altă valoare a metricii.
Ei bine, adică: în ce măsură este acesta un atribut de clasificare (am văzut cea mai clară explicație în limba rusă pe RandomForest aici).

Cod R muncitor-țăran pentru procesarea unui set de date cu rezultatele testelor de încărcare:

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

Puteți selecta direct hiperparametrii algoritmului cu mâinile și, concentrându-vă pe calitatea modelului, să selectați un model care îndeplinește cu mai multă acuratețe predicțiile din setul de date de validare.
Puteți scrie un fel de funcție pentru această lucrare (apropo, din nou, folosind un fel de algoritm de optimizare).

Puteți utiliza pachetul R caret, nu ideea este importantă.

Ca urmare, în acest caz, se obține următorul rezultat pentru a evalua gradul de importanță a atributelor:

Metoda științifică poke sau cum să selectați o configurație de bază de date folosind benchmark-uri și un algoritm de optimizare

Bine. Astfel, putem începe reflecția globală:

  1. Se pare că cel mai semnificativ, în aceste condiții de testare, a fost parametrul commit_wait
    Din punct de vedere tehnic, specifică modul de execuție al operației io de scriere a datelor redo din bufferul de jurnal subdb în grupul de jurnal curent: sincron sau asincron.
    Valoare nowait ceea ce are ca rezultat o creștere aproape verticală, multiplă a valorii metricii tps: aceasta este includerea modului io asincron în grupurile redo.
    O întrebare separată este dacă ar trebui sau nu să faceți acest lucru într-o bază de date cu alimente. Aici mă limitez la a afirma: acesta este un factor semnificativ.
  2. Este logic ca dimensiunea tamponului de jurnal al subd: se dovedește a fi un factor semnificativ.
    Cu cât dimensiunea tamponului de jurnal este mai mică, cu atât capacitatea sa de stocare este mai mică, cu atât se depășește mai des și/sau incapacitatea de a aloca o zonă liberă în el pentru o porțiune de date redox noi.
    Aceasta înseamnă: întârzieri asociate cu alocarea spațiului în memoria tampon de jurnal și/sau descărcarea datelor de refacere din acesta în grupuri de refacere.
    Aceste întârzieri, desigur, ar trebui să afecteze și chiar afectează randamentul bazei de date pentru tranzacții.
  3. Parametru db_block_checksum: ei bine, de asemenea, în general, este clar - procesarea tranzacțiilor duce la formarea de blocuri darty în memoria tampon a subbazei de date.
    Care, atunci când verificarea sumelor de control ale blocurilor de date este activată, baza de date trebuie să o proceseze - să calculeze aceste sume de control din corpul blocului de date, să le verifice cu ceea ce este scris în antetul blocului de date: se potrivește/nu se potrivește.
    O astfel de muncă, din nou, nu poate decât să întârzie procesarea datelor și, în consecință, parametrul și mecanismul care stabilește acest parametru se dovedesc a fi semnificative.
    De aceea, furnizorul oferă, în documentația pentru acest parametru, diferite valori pentru acesta (parametrul) și notează că da, va exista un impact, dar, ei bine, puteți alege diferite valori, până la „off” și impacturi diferite.

Ei bine, o concluzie globală.

Abordarea, în general, se dovedește a fi destul de funcțională.

El își permite destul de mult, în etapele incipiente ale testării sarcinii unui anumit sistem de service, pentru a-și selecta configurația optimă (sistemului) pentru sarcină, să nu aprofundeze prea mult în specificul instalării sistemului pentru sarcină.

Dar nu o exclude complet - cel puțin la nivel de înțelegere: sistemul trebuie să fie cunoscut despre „butoanele de reglare” și intervalele de rotație permise ale acestor butoane.

Abordarea poate găsi apoi relativ rapid configurația optimă a sistemului.
Și pe baza rezultatelor testării, este posibil să obțineți informații despre natura relației dintre metricile de performanță a sistemului și valorile parametrilor setărilor sistemului.

Ceea ce, desigur, ar trebui să contribuie la apariția acestei înțelegeri foarte profunde a sistemului, a funcționării acestuia, cel puțin sub o anumită sarcină.

În practică, acesta este un schimb de costuri de înțelegere a sistemului personalizat cu costurile de pregătire a unei astfel de testari a sistemului.

Aș dori să notez separat: în această abordare, gradul de adecvare a testării sistemului la condițiile de funcționare pe care le va avea în funcționarea comercială este de o importanță critică.

Vă mulțumim pentru atenție și timp.

Sursa: www.habr.com

Adauga un comentariu