A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével

Helló

Úgy döntöttem, megosztom a leletemet – a gondolat, a próba és a hiba gyümölcsét.
Nagyjából: ez persze nem lelet - mindezt már régen tudnia kellett volna azoknak, akik bármilyen rendszer alkalmazott statisztikai adatfeldolgozásában és optimalizálásában vesznek részt, nem feltétlenül konkrétan a DBMS-ben.
És: igen, tudják, érdekes cikkeket írnak a kutatásaikról, példa (UPD.: a kommentekben egy nagyon érdekes projektet emeltek ki: ottertune )
Másrészt: az informatikusok, a DBA körében nem látok széles körben említést vagy terjesztést erről a megközelítésről az interneten.

Szóval a lényegre.

Tételezzük fel, hogy van egy feladatunk: felállítani egy szolgáltatási rendszert valamilyen munka kiszolgálására.

Ismeretes erről a munkáról: mi az, hogyan mérik ennek a munkának a minőségét, és mi a minőség mérésének kritériuma.

Tételezzük fel azt is, hogy többé-kevésbé ismert és érthető: pontosan hogyan történik a munka ebben a szolgáltatási rendszerben (vagy azzal).

„Többé-kevésbé” - ez azt jelenti, hogy el lehet készíteni (vagy beszerezni valahonnan) egy bizonyos eszközt, segédprogramot, szolgáltatást, amely szintetizálható és a rendszerre alkalmazható tesztterheléssel kellően megfelelő ahhoz, ami a gyártásban lesz, a termelésben való munkavégzéshez kellően megfelelő körülmények között.

Nos, tegyük fel, hogy ehhez a szolgáltatási rendszerhez ismertek a beállítási paraméterek, amelyek segítségével a rendszer konfigurálható a munka termelékenysége szempontjából.

És mi a probléma - nincs kellően teljes körű megértése ennek a szolgáltatási rendszernek, amely lehetővé teszi a rendszer beállításainak szakszerű konfigurálását az adott platform jövőbeli terheléséhez, és elérheti a rendszer szükséges termelékenységét.

Jól. Ez szinte mindig így van.

Mit lehet itt csinálni?

Nos, az első dolog, ami eszünkbe jut, az az, hogy nézzük meg a rendszer dokumentációját. Értse meg, melyek a beállítási paraméterek értékeinek elfogadható tartományai. És például a koordináta süllyedés módszerével válassza ki a rendszerparaméterek értékeit a tesztekben.

Azok. adjon meg a rendszernek valamilyen konfigurációt a konfigurációs paramétereinek meghatározott értékkészlete formájában.

Vigyen fel rá egy próbaterhelést ezzel az eszköz-segédprogrammal, a terhelésgenerátorral.
És nézd meg az értéket – a választ, vagy a rendszer minőségének mérőszámát.

A második gondolat lehet az a következtetés, hogy ez nagyon hosszú idő.

Nos, ez: ha sok a beállítási paraméter, ha nagyok a lefutott értéktartományok, ha minden egyes terhelési teszt elvégzése sok időt vesz igénybe, akkor: igen, mindez elfogadhatatlanul eltarthat hosszú idő.

Nos, itt van, amit megérthet és emlékezhet.

Megtudhatja, hogy a szolgáltatási rendszer beállítási paramétereinek értékkészletében van egy vektor, néhány érték sorozataként.

Minden ilyen vektor, ha más tényezők megegyeznek (annyiban, hogy ez a vektor nem befolyásolja), a metrika egy teljesen meghatározott értékének felel meg - a rendszer tesztterhelés alatti működésének minőségi mutatója.

Ie

Jelöljük a rendszerkonfigurációs vektort mint A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségévelAhol A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével; Ahol A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével — a rendszerkonfigurációs paraméterek száma, hány ilyen paraméter van.

És az ennek megfelelő mérőszám értéke A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével jelöljük úgy
A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével, akkor kapunk egy függvényt: A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével

Nos, akkor: minden egyből az én esetemben a következő: diákkoromból szinte elfeledett algoritmusok egy függvény szélsőértékének kereséséhez.

Oké, de itt felvetődik egy szervezeti és alkalmazott kérdés: melyik algoritmust érdemes használni.

  1. Abban az értelemben – hogy kevesebbet tudjon kézzel kódolni.
  2. És hogy működjön, i.e. megtalálta az extrémumot (ha van), nos, legalábbis gyorsabb, mint a koordináta süllyedés.

Az első pont arra utal, hogy olyan környezetek felé kell tekintenünk, amelyekben már implementáltak ilyen algoritmusokat, és valamilyen formában készen állnak a kódban való használatra.
Nos, tudom python и cran-r

A második pont azt jelenti, hogy olvasni kell magukról az algoritmusokról, mik ezek, mik a követelményeik, munkájuk jellemzői.

És amit adnak, azok hasznos mellékhatások lehetnek - eredmények, vagy közvetlenül az algoritmusból.

Vagy az algoritmus eredményeiből nyerhetők ki.

Sok múlik a beviteli feltételeken.

Például, ha valamilyen oknál fogva gyorsabban kell eredményt elérnie, akkor a gradiens süllyedési algoritmusok felé kell néznie, és választania kell közülük.

Vagy ha az idő nem annyira fontos, használhat például sztochasztikus optimalizálási módszereket, például genetikai algoritmust.

Ennek a megközelítésnek a munkáját, a rendszerkonfiguráció kiválasztását, genetikai algoritmus segítségével javaslom a következő, úgymond laboratóriumi munkában megfontolni.

A kezdeti:

  1. Legyen szolgáltatási rendszerként: oracle xe 18c
  2. Legyen ez szolgálja a tranzakciós tevékenységet és a célt: az aladatbázis lehető legmagasabb átviteli sebességét, tranzakció/sec-ben.
  3. A tranzakciók nagyon eltérőek lehetnek az adatokkal való munka jellegét és a munkakörnyezetet tekintve.
    Egyezzünk meg abban, hogy ezek olyan tranzakciók, amelyek nem dolgoznak fel nagy mennyiségű táblázatos adatot.
    Abban az értelemben, hogy nem generálnak több visszavonási adatot, mint újra, és nem dolgozzák fel a sorok és nagy táblázatok nagy százalékát.

Ezek olyan tranzakciók, amelyek egy többé-kevésbé nagy tábla egy sort módosítanak, és ezen a táblán kevés index található.

Ebben a helyzetben: a tranzakciók feldolgozására szolgáló aladatbázis termelékenységét fenntartással a redox adatbázis általi feldolgozás minősége határozza meg.

Felelősség kizárása - ha kifejezetten a subdb beállításokról beszélünk.

Mert általános esetben előfordulhatnak például tranzakciós zárolások az SQL munkamenetek között, a táblázatos adatokkal végzett felhasználói munka tervezése és/vagy a táblázatos modell miatt.

Ami persze leszorító hatással lesz a TPS metrikára, és ez exogén tényező lesz, az aladatbázishoz képest: nos, így készült a táblázatos modell és a benne lévő adatokkal való munka, hogy blokkolások lépnek fel.

Ezért a kísérlet tisztasága érdekében ezt a tényezőt kizárjuk, és az alábbiakban pontosítom, hogyan.

  1. Tegyük fel a határozottság kedvéért, hogy az adatbázisba beküldött SQL parancsok 100%-a DML parancs.
    Legyen az aladatbázissal végzett felhasználói munka jellemzői ugyanazok a tesztekben.
    Mégpedig: az skl munkamenetek száma, táblázatos adatok, az skl munkamenetek működése ezekkel.
  2. A Subd működik FORCE LOGGING, ARCHIVELOG módok. A Flashback-adatbázis mód ki van kapcsolva a subd szintjén.
  3. Újrakészítő naplók: külön fájlrendszerben, külön „lemezen” találhatók;
    Az adatbázis többi fizikai összetevője: egy másik, külön fájlrendszerben, külön „lemezen”:

További részletek a fizikai eszközről. laboratóriumi adatbázis-összetevők

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

Kezdetben ilyen terhelési feltételek mellett a tranzakciós subd-t akartam használni SLOB-utility
Van egy csodálatos tulajdonsága, idézem a szerzőt:

A SLOB középpontjában a „SLOB módszer” áll. A SLOB módszer célja a platformok tesztelése
pályázati vita nélkül. Nem lehet maximális hardverteljesítményt elérni
olyan alkalmazáskód használatával, amelyet például az alkalmazás zárolása köt, vagy akár
Oracle Database blokkok megosztása. Így van – az adatok megosztása többletköltséggel jár
adatblokkban! De a SLOB – az alapértelmezett telepítésében – immunis az ilyen vitákra.

Ez a nyilatkozat: megfelel, az.
Kényelmes szabályozni a cl munkamenetek párhuzamosságának mértékét, ez a kulcs -t indítsa el a segédprogramot runit.sh a SLOB-tól
A DML parancsok százalékos aránya szabályozva van, a subd-nek küldött szöveges üzenetek számában, minden szöveges munkamenetben, paraméterben UPDATE_PCT
Külön és nagyon kényelmesen: SLOB maga, a betöltési munkamenet előtt és után – statspack-et vagy awr-snapshots-ot készít (amit kell elkészíteni).

Az azonban kiderült SLOB nem támogatja a 30 másodpercnél rövidebb időtartamú SQL-munkameneteket.
Ezért először a saját, munkás-paraszt verziómat kódoltam a rakodóból, majd az üzemben maradt.

Hadd tisztázzam, mit és hogyan csinál a rakodó az egyértelműség kedvéért.
A betöltő lényegében így néz ki:

Munkás kód

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

A dolgozókat a következőképpen indítják:

Futó munkások

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

És a dolgozók asztalai így készülnek:

Táblázatok készítése

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"

Azok. Minden dolgozóhoz (gyakorlatilag: külön SQL munkamenet a DB-ben) külön tábla készül, amellyel a dolgozó dolgozik.

Ez biztosítja a tranzakciós zárolások hiányát a dolgozói munkamenetek között.
Minden dolgozó: ugyanazt csinálja, a saját asztalával, az asztalok mind egyformák.
Minden dolgozó ugyanannyi ideig végez munkát.
Sőt, elég hosszú ideig ahhoz, hogy például egy naplóváltás biztosan bekövetkezzen, és többször is.
Nos, ennek megfelelően felmerültek a kapcsolódó költségek és hatások.
Az én esetemben a dolgozók munkaidejét 8 percre állítottam be.

A statspack jelentés egy darabja, amely leírja a subd működését terhelés alatt

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

Visszatérve a laboratóriumi munkához.
A laboratóriumi aladatbázis alábbi paramétereinek értékeit változtatjuk, ha egyéb dolgok megegyeznek:

  1. Adatbázis-naplócsoportok mérete. értéktartomány: [32, 1024] MB;
  2. A folyóiratcsoportok száma az adatbázisban. értéktartomány: [2,32];
  3. log_archive_max_processes értéktartomány: [1,8];
  4. commit_logging két érték megengedett: batch|immediate;
  5. commit_wait két érték megengedett: wait|nowait;
  6. log_buffer értéktartomány: [2,128] MB.
  7. log_checkpoint_timeout értéktartomány: [60,1200] másodperc
  8. db_writer_processes értéktartomány: [1,4]
  9. undo_retention értéktartomány: [30;300] másodperc
  10. transactions_per_rollback_segment értéktartomány: [1,8]
  11. disk_asynch_io két érték megengedett: true|false;
  12. filesystemio_options a következő értékek megengedettek: none|setall|directIO|asynch;
  13. db_block_checking a következő értékek megengedettek: OFF|LOW|MEDIUM|FULL;
  14. db_block_checksum a következő értékek megengedettek: OFF|TYPICAL|FULL;

Az Oracle adatbázisok karbantartásában jártas ember már biztosan meg tudja mondani, hogy a megadott paraméterekből és azok elfogadható értékéből mit és milyen értékeket kell beállítani, hogy az adatbázis nagyobb termelékenységet érjen el az általa jelzett adatokkal végzett munka során. az alkalmazás kódja, itt fent.

De.

A laboratóriumi munka lényege, hogy megmutassa, maga az optimalizáló algoritmus ezt viszonylag gyorsan tisztázza számunkra.

Nekünk nem marad más hátra, mint a személyre szabható rendszeren keresztül belenézni a dokumentumba, csak annyit, hogy megtudjuk, milyen paramétereken és milyen tartományokban kell változtatni.
És még: kódolja azt a kódot, amely a kiválasztott optimalizálási algoritmus egyedi rendszerével való együttműködéshez fog használni.

Tehát most a kódról.
Fentebb beszéltem róla cran-r, azaz: a testreszabott rendszerrel végzett összes manipulációt egy R-szkript formájában rendezik.

Az aktuális feladat, elemzés, metrikus érték szerinti kiválasztás, rendszerállapotvektorok: ez egy csomag GA (a dokumentáció)
A csomag ebben az esetben nem túl alkalmas abban az értelemben, hogy azt várja el, hogy a vektorok (ha a csomag szempontjából kromoszómák) számsorok formájában legyenek megadva tört résszel.

És az én vektorom a beállítási paraméterek értékeiből: ez 14 mennyiség - egész számok és karakterláncértékek.

A probléma természetesen könnyen elkerülhető, ha a karakterláncértékekhez bizonyos számokat rendelünk.

Így a végén az R szkript fő darabja így néz ki:

Hívja a 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

Itt, a segítséggel lower и upper szubrutin attribútumok ga lényegében a keresési tér egy területe van megadva, amelyen belül olyan vektort (vagy vektorokat) keresnek, amelyekre a fitnesz függvény maximális értékét kapjuk.

A ga szubrutin a fitnesz funkciót maximalizáló keresést hajt végre.

Nos, akkor kiderül, hogy ebben az esetben az alkalmassági függvénynek, amely a vektort a subd bizonyos paramétereinek értékkészleteként értelmezi, metrikát kell kapnia a subd-től.

Azaz: hány, adott subd beállítással és adott terhelés mellett a subd: a subd feldolgozza a tranzakciókat másodpercenként.

Vagyis kibontáskor a fitnesz funkción belül a következő többlépést kell végrehajtani:

  1. A számok bemeneti vektorának feldolgozása - átalakítása a részadat-paraméterek értékévé.
  2. Kísérlet adott számú, adott méretű újrakészítési csoport létrehozására. Sőt, a próbálkozás sikertelen is lehet.
    Az aldban már létező folyóiratcsoportok, bizonyos mennyiségben és méretben, a kísérlet tisztasága érdekében - d.b. törölve.
  3. Ha az előző pont sikeres: konfigurációs paraméterek értékeinek megadása az adatbázisban (ismét: hiba lehet)
  4. Ha az előző lépés sikeres: a subd leállítása, a subd elindítása, hogy az újonnan megadott paraméterértékek érvénybe lépjenek. (megint: hiba lehet)
  5. Ha az előző lépés sikeres: végezzen terhelési tesztet. mérőszámok lekérése a subd-ből.
  6. Állítsa vissza a subd-t eredeti állapotába, azaz. töröljön további naplócsoportokat, és állítsa vissza az eredeti aladatbázis-konfigurációt.

Fitness funkció kódja

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

Hogy. minden munka: a fitnesz funkcióban végzett.

A ga-szubrutin vektorokat, pontosabban kromoszómákat dolgoz fel.
Amelyben számunkra a legfontosabb a kromoszómák kiválasztása olyan génekkel, amelyekre a fitnesz függvény nagy értékeket produkál.

Lényegében ez a kromoszómák optimális halmazának megkeresése egy N-dimenziós keresési térben lévő vektor segítségével.

Nagyon világos, részletes magyarázat, az R-kód példáival, egy genetikai algoritmus munkája.

Két technikai szempontot szeretnék külön kiemelni.

Kiegészítő hívások a függvényből evaluatealapján történik például a stop-start, a subd paraméter értékének beállítása cran-r funkciókat system2

Aminek segítségével: valamilyen bash szkript vagy parancs meghívódik.

Például:

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

A második pont a vonal, evaluate funkciókat, egy adott metrikaérték és a hozzá tartozó hangolási vektor naplófájlba mentésével:

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

Ez azért fontos, mert ebből az adattömbből további információt lehet majd szerezni arról, hogy a hangolóvektor mely összetevőinek van kisebb vagy nagyobb hatása a metrika értékére.

Azaz: lehetőség lesz attribútum-importamce elemzés elvégzésére.

Szóval mi történhet?

Grafikon formájában, ha a teszteket növekvő metrikus sorrendben rendeli, a kép a következő:

A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével

Néhány adat a metrika szélső értékeinek megfelelően:
A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével
Itt, az eredményeket tartalmazó képernyőképen pontosítom: a hangolóvektor értékei a fitnesz függvény kódjában vannak megadva, nem a paraméterek/paraméterérték-tartományok számlistájában, ami megfogalmazásra került. fent a szövegben.

Jól. Sok vagy kevés, ~8ezer tps: külön kérdés.
A laboratóriumi munka keretein belül ez a szám nem lényeges, fontos a dinamika, ez az érték hogyan változik.

A dinamika itt jó.
Nyilvánvaló, hogy legalább egy tényező jelentősen befolyásolja a metrika értékét, a ga-algoritmus, a kromoszómavektorok válogatását: fedett.
A görbeértékek meglehetősen erőteljes dinamikájából ítélve van még legalább egy tényező, amely bár lényegesen kisebb, de hatással van.

Itt van rá szüksége attribute-importance elemzést, hogy megértsük, milyen attribútumok (jó, ebben az esetben a hangolóvektor komponensei) és mennyire befolyásolják a metrika értékét.
És ebből az információból: tudja meg, hogy milyen tényezőket befolyásoltak a jelentős attribútumok változásai.

Végrehajt attribute-importance különböző módokon lehetséges.

Ebből a célból szeretem az algoritmust randomForest R csomag azonos nevű (a dokumentáció)
randomForest, ahogy általában véve értem a munkáját, és különösen az attribútumok fontosságának felmérésére irányuló megközelítését, egy bizonyos modellt épít fel a válaszváltozó attribútumoktól való függésére.

Esetünkben a válaszváltozó egy mérőszám, amelyet terhelési tesztek során nyerünk az adatbázisból: tps;
Az attribútumok pedig a hangolóvektor összetevői.

Ezért itt randomForest két számmal értékeli az egyes modellattribútumok fontosságát: %IncMSE — ennek az attribútumnak a jelenléte/hiánya egy modellben hogyan változtatja meg a modell MSE minőségét (átlagos négyzetes hiba);

Az IncNodePurity pedig egy olyan szám, amely azt tükrözi, hogy ennek az attribútumnak az értékei alapján mennyire jól osztható fel egy megfigyeléseket tartalmazó adathalmaz úgy, hogy az egyik részben a metrika egyik értékével magyarázható adatok, a másikban pedig a mérőszám másik értéke.
Nos, ez: mennyiben osztályozó tulajdonság (a legvilágosabb, orosz nyelvű magyarázatot a RandomForest-en láttam itt).

Munkás-paraszt R-kód egy adathalmaz feldolgozásához a terhelési tesztek eredményeivel:

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

Közvetlenül kézzel kiválaszthatja az algoritmus hiperparamétereit, és a modell minőségére összpontosítva kiválaszthatja azt a modellt, amely pontosabban teljesíti az érvényesítési adatkészleten szereplő előrejelzéseket.
Ehhez a munkához írhatunk valamilyen függvényt (egyébként ismét valamilyen optimalizáló algoritmus segítségével).

Használhatja az R csomagot caret, nem a lényeg a fontos.

Ennek eredményeként ebben az esetben a következő eredményt kapjuk az attribútumok fontosságának felmérésére:

A tudományos poke módszer, avagy hogyan válasszunk adatbázis-konfigurációt benchmarkok és optimalizálási algoritmus segítségével

Jól. Így elkezdhetjük a globális gondolkodást:

  1. Kiderült, hogy ezen vizsgálati körülmények között a legjelentősebb a paraméter volt commit_wait
    Technikailag meghatározza a subdb naplópufferből az aktuális naplócsoportba történő újraírási adatok írásának io műveletének végrehajtási módját: szinkron vagy aszinkron.
    Érték nowait ami a tps metrika értékének szinte függőleges, többszörös növekedését eredményezi: ez az aszinkron io mód felvétele a redo csoportokba.
    Külön kérdés, hogy ezt meg kell-e tenni egy élelmiszer-adatbázisban vagy sem. Itt csak arra szorítkozom, hogy kijelentsem: ez jelentős tényező.
  2. Logikus, hogy a subd: napló pufferének mérete jelentős tényezőnek bizonyul.
    Minél kisebb a naplópuffer mérete, annál kisebb a pufferkapacitása, annál gyakrabban csordul túl és/vagy nem tud szabad területet lefoglalni benne az új redox adatok egy részének.
    Ez a következőket jelenti: késések, amelyek a naplópufferben lévő helyfoglaláshoz és/vagy az ismétlési adatok ismételt csoportokba való kiírásához kapcsolódnak.
    Ezeknek a késéseknek természetesen hatással kell lenniük a tranzakciók adatbázisának átvitelére.
  3. Paraméter db_block_checksum: nos, általánosságban is egyértelmű - a tranzakciófeldolgozás darty blokkok kialakulásához vezet az aladatbázis puffer-gyorsítótárában.
    Amit, ha az adatblokkok ellenőrző összegeinek ellenőrzése engedélyezve van, az adatbázisnak fel kell dolgoznia - ezeket az ellenőrző összegeket ki kell számítani az adatblokk törzséből, ellenőrizni kell az adatblokk fejlécében leírtakkal: egyezik/nem egyezik.
    Az ilyen munka ismét csak késleltetheti az adatfeldolgozást, és ennek megfelelően a paraméter és a paramétert beállító mechanizmus jelentősnek bizonyul.
    Ezért a szállító a dokumentációban ehhez a paraméterhez különböző értékeket kínál (a paraméterhez), és megjegyzi, hogy igen, lesz hatása, de hát, választhat különböző értékeket, egészen az „off”-ig, ill. különböző hatások.

Nos, globális következtetés.

A megközelítés általában véve nagyon működőképesnek bizonyul.

Nagyon megengedi magának, hogy egy bizonyos szolgáltatási rendszer terhelési tesztelésének korai szakaszában annak (rendszer) optimális konfigurációjának kiválasztása érdekében a terheléshez ne nyúljon bele túlságosan a rendszer terhelésre történő beállításának sajátosságaiba.

De ez nem zárja ki teljesen - legalábbis a megértés szintjén: a rendszernek ismernie kell a „beállító gombokat” és ezeknek a gomboknak a megengedett forgási tartományát.

A megközelítés ekkor viszonylag gyorsan megtalálja az optimális rendszerkonfigurációt.
És a tesztelés eredményei alapján információkat lehet szerezni a rendszer teljesítménymutatói és a rendszerbeállítási paraméterek értékei közötti kapcsolat természetéről.

Aminek persze hozzá kell járulnia ahhoz, hogy legalább adott terhelés mellett kialakuljon ez a nagyon mély megértése a rendszernek, működésének.

A gyakorlatban ez a testreszabott rendszer megértésének költségeinek és a rendszer ilyen tesztelésének előkészítésének költségeinek felcserélése.

Külön szeretném megjegyezni: ebben a megközelítésben kritikus fontosságú, hogy a rendszertesztelés milyen mértékben feleljen meg az üzemi feltételeknek, amelyek a kereskedelmi üzemben lesznek.

Köszönöm a figyelmet és az időt.

Forrás: will.com

Hozzászólás