O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización

Ola

Decidín compartir o meu achado, froito do pensamento, do ensaio e do erro.
En xeral: este non é un achado, por suposto; todo isto debería ser coñecido desde hai moito tempo para aqueles que están implicados no procesamento de datos estatísticos aplicados e na optimización de calquera sistema, non necesariamente especificamente o DBMS.
E: si, saben, escriben artigos interesantes sobre as súas investigacións, exemplo (UPD.: nos comentarios sinalaron un proxecto moi interesante: ottertune )
Por outra banda: non vexo ningunha mención ou difusión xeneralizada deste enfoque en Internet entre os especialistas en informática, DBA.

Entón, ata o punto.

Supoñamos que temos unha tarefa: configurar un determinado sistema de servizos para atender algún tipo de traballo.

Sábese deste traballo: que é, como se mide a calidade deste traballo e cal é o criterio para medir esta calidade.

Supoñamos tamén que é máis ou menos coñecido e entendido: exactamente como se traballa en (ou con) este sistema de servizos.

"Máis ou menos" - isto significa que é posible preparar (ou obtelo desde algún lugar) unha determinada ferramenta, utilidade, servizo que se pode sintetizar e aplicar ao sistema cunha carga de proba suficientemente adecuada ao que estará en produción, en condicións suficientemente adecuadas para traballar na produción .

Ben, supoñamos que se coñece un conxunto de parámetros de axuste para este sistema de servizos, que se poden usar para configurar este sistema en función da produtividade do seu traballo.

E cal é o problema: non hai unha comprensión suficientemente completa deste sistema de servizos, que lle permita configurar de forma experta a configuración deste sistema para a carga futura nunha plataforma determinada e obter a produtividade necesaria do sistema.

Ben. Este é case sempre o caso.

Que podes facer aquí?

Ben, o primeiro que se me ocorre é mirar a documentación deste sistema. Comprender cales son os intervalos aceptables para os valores dos parámetros de axuste. E, por exemplo, usando o método de descenso de coordenadas, seleccione os valores para os parámetros do sistema nas probas.

Eses. darlle ao sistema algún tipo de configuración, en forma dun conxunto específico de valores para os seus parámetros de configuración.

Aplícalle unha carga de proba, usando este xerador de carga de utilidade.
E mira o valor: a resposta ou unha métrica da calidade do sistema.

O segundo pensamento pode ser a conclusión de que isto é moito tempo.

Ben, é dicir: se hai moitos parámetros de configuración, se os intervalos dos seus valores que se executan son grandes, se cada proba de carga individual leva moito tempo en completarse, entón: si, todo isto pode levar un tempo inaceptable. Moito tempo.

Ben, aquí tes o que podes entender e lembrar.

Podes descubrir que no conxunto de valores dos parámetros de configuración do sistema de servizo hai un vector, como unha secuencia dalgúns valores.

Cada un destes vectores, sendo o resto de elementos iguais (no que non se ve afectado por este vector), corresponde a un valor completamente definido da métrica, un indicador da calidade do funcionamento do sistema baixo unha carga de proba.

Ie

Denotemos o vector de configuración do sistema como O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimizaciónonde O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización; Onde O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización — número de parámetros de configuración do sistema, cantos destes parámetros hai.

E o valor da métrica correspondente a esta O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización denotémolo como
O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización, entón obtemos unha función: O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización

Ben, entón: todo se reduce de inmediato a, no meu caso: case esquecido dos meus tempos de estudante, algoritmos para buscar o extremo dunha función.

Vale, pero aquí xorde unha pregunta organizativa e aplicada: que algoritmo usar.

  1. No sentido - para que poida codificar menos a man.
  2. E para que funcione, é dicir. atopou o extremo (se o hai), ben, polo menos máis rápido que o descenso coordenado.

O primeiro punto indica que debemos mirar para algúns ambientes nos que tales algoritmos xa foron implementados, e están, dalgunha forma, listos para usar en código.
Ben, sei python и cran-r

O segundo punto significa que cómpre ler sobre os propios algoritmos, cales son, cales son os seus requisitos e as características do seu traballo.

E o que dan poden ser efectos secundarios útiles: resultados ou directamente do propio algoritmo.

Ou poden obterse a partir dos resultados do algoritmo.

Depende moito das condicións de entrada.

Por exemplo, se, por algún motivo, necesitas obter un resultado máis rápido, ben, tes que buscar algoritmos de descenso de gradientes e escoller un deles.

Ou, se o tempo non é tan importante, pode, por exemplo, utilizar métodos de optimización estocástica, como un algoritmo xenético.

Propoño considerar o traballo deste enfoque, seleccionando a configuración do sistema, mediante un algoritmo xenético, no seguinte, por así dicir: traballo de laboratorio.

Orixinal:

  1. Que exista, como sistema de servizos: oracle xe 18c
  2. Deixa que sirva á actividade transaccional e ao obxectivo: obter o maior rendemento posible da subbase de datos, en transaccións/s.
  3. As transaccións poden ser moi diferentes na natureza de traballar con datos e no contexto de traballo.
    Imos de acordo en que se trata de transaccións que non procesan unha gran cantidade de datos tabulares.
    No sentido de que non xeran máis datos desfacer que refacer e non procesan grandes porcentaxes de filas e táboas grandes.

Trátase de transaccións que cambian unha fila nunha táboa máis ou menos grande, cun pequeno número de índices nesta táboa.

Nesta situación: a produtividade da subbase de datos para o procesamento de transaccións estará determinada, con reserva, pola calidade do procesamento da base de datos redox.

Descargo de responsabilidade - se falamos específicamente da configuración de subdb.

Porque, no caso xeral, pode haber, por exemplo, bloqueos transaccionais entre sesións SQL, debido ao deseño do traballo do usuario con datos tabulares e/ou modelo tabular.

O que, por suposto, terá un efecto deprimente na métrica TPS e este será un factor esóxeno, en relación á subbase de datos: así foi como se deseñou o modelo tabular e o traballo con datos nel que se producen bloqueos.

Polo tanto, para a pureza do experimento, excluiremos este factor e a continuación aclararei exactamente como.

  1. Supoñamos, para máis certeza, que o 100% dos comandos SQL enviados á base de datos son comandos DML.
    Que as características do traballo do usuario coa subbase de datos sexan as mesmas nas probas.
    A saber: o número de sesións skl, datos tabulares, como funcionan as sesións skl con elas.
  2. Subd traballa en FORCE LOGGING, ARCHIVELOG mods. O modo de base de datos flashback está desactivado, no nivel subd.
  3. Refacer rexistros: situado nun sistema de ficheiros separado, nun "disco" separado;
    O resto do compoñente físico da base de datos: noutro sistema de ficheiros separado, nun "disco" separado:

Máis detalles sobre o dispositivo físico. compoñentes de bases de datos de laboratorio

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

Inicialmente, nestas condicións de carga, quería usar transacción subd SLOB-utilidade
Ten unha característica tan marabillosa, citarei ao autor:

No corazón de SLOB está o "método SLOB". O Método SLOB ten como obxectivo probar plataformas
sen disputa de aplicación. Non se pode impulsar o máximo rendemento do hardware
usando código de aplicación que, por exemplo, está ligado ao bloqueo de aplicacións ou mesmo
compartir bloques de base de datos Oracle. É certo: hai unha sobrecarga ao compartir datos
en bloques de datos! Pero SLOB, no seu despregue predeterminado, é inmune a tal contención.

Esta declaración: corresponde, é.
É conveniente regular o grao de paralelismo das sesións cl, esta é a clave -t iniciar a utilidade runit.sh de SLOB
A porcentaxe de comandos DML está regulada, no número de mensaxes de texto que se envían ao subd, cada sesión de texto, parámetro UPDATE_PCT
Por separado e moi cómodo: SLOB el mesmo, antes e despois da sesión de carga: prepara un paquete de estatísticas ou awr-snapshots (o que está configurado para ser preparado).

Con todo, resultou que SLOB non admite sesións SQL cunha duración inferior a 30 segundos.
Polo tanto, primeiro codifiquei a miña propia versión obreira-campesiña do cargador e despois quedou en funcionamento.

Déixeme aclarar o que fai o cargador e como o fai, para que quede claro.
Esencialmente, o cargador ten o seguinte aspecto:

Código do traballador

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

Os traballadores póñense en marcha deste xeito:

Traballadores en execución

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

E as táboas para os traballadores prepáranse así:

Creación de táboas

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"

Eses. Para cada traballador (practicamente: unha sesión SQL separada na base de datos) créase unha táboa separada, coa que traballa o traballador.

Isto garante a ausencia de bloqueos transaccionais entre as sesións dos traballadores.
Cada traballador: fai o mesmo, coa súa propia mesa, as mesas son todas iguais.
Todos os traballadores realizan o mesmo traballo durante o mesmo tempo.
Ademais, durante un tempo suficiente para que, por exemplo, un cambio de rexistro ocorrería definitivamente, e máis dunha vez.
Ben, en consecuencia, xurdiron custos e efectos asociados.
No meu caso, configurei a duración do traballo dos traballadores en 8 minutos.

Unha peza dun informe de statspack que describe o funcionamento do subd baixo carga

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

Volvendo ao traballo de laboratorio.
En igualdad de condicións, variaremos os valores dos seguintes parámetros da subbase de datos do laboratorio:

  1. Tamaño dos grupos de rexistro de bases de datos. intervalo de valores: [32, 1024] MB;
  2. Número de grupos de revistas na base de datos. intervalo de valores: [2,32];
  3. log_archive_max_processes intervalo de valores: [1,8];
  4. commit_logging permítense dous valores: batch|immediate;
  5. commit_wait permítense dous valores: wait|nowait;
  6. log_buffer intervalo de valores: [2,128] MB.
  7. log_checkpoint_timeout intervalo de valores: [60,1200] segundos
  8. db_writer_processes intervalo de valores: [1,4]
  9. undo_retention intervalo de valores: [30;300] segundos
  10. transactions_per_rollback_segment intervalo de valores: [1,8]
  11. disk_asynch_io permítense dous valores: true|false;
  12. filesystemio_options permítense os seguintes valores: none|setall|directIO|asynch;
  13. db_block_checking permítense os seguintes valores: OFF|LOW|MEDIUM|FULL;
  14. db_block_checksum permítense os seguintes valores: OFF|TYPICAL|FULL;

Unha persoa con experiencia no mantemento de bases de datos Oracle xa pode dicir que e a que valores se deben establecer, a partir dos parámetros especificados e os seus valores aceptables, para obter unha maior produtividade da base de datos para o traballo cos datos indicados por o código da aplicación, aquí arriba.

Pero.

O obxectivo do traballo de laboratorio é demostrar que o propio algoritmo de optimización aclarará isto con relativa rapidez.

A nós só nos queda mirar o documento, a través do sistema personalizable, o suficiente para saber que parámetros cambiar e en que rangos.
E tamén: codificar o código que se utilizará para traballar co sistema personalizado do algoritmo de optimización seleccionado.

Entón, agora sobre o código.
Falei máis arriba sobre cran-r, é dicir: todas as manipulacións co sistema personalizado orquestráranse en forma de script R.

A tarefa real, análise, selección por valor métrico, vectores de estado do sistema: este é un paquete GA (a documentación)
O paquete, neste caso, non é moi axeitado, no sentido de que espera que os vectores (cromosomas, se en termos do paquete) se especifiquen en forma de cadeas de números cunha parte fraccionaria.

E o meu vector, a partir dos valores dos parámetros de configuración: son 14 cantidades: enteiros e valores de cadea.

O problema, por suposto, evítase facilmente asignando algúns números específicos a valores de cadea.

Así, ao final, a peza principal do script R ten o seguinte aspecto:

Chamar 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

Aquí, coa axuda lower и upper atributos de subrutina ga esencialmente, especifícase unha área do espazo de busca, dentro da cal se realizará unha busca de tal vector (ou vectores) para os que se obterá o valor máximo da función de aptitude.

A subrutina ga realiza unha busca maximizando a función de fitness.

Ben, entón, resulta que, neste caso, é necesario que a función de fitness, entendendo o vector como un conxunto de valores para determinados parámetros do subd, reciba unha métrica do subd.

É dicir: cantos, cunha determinada configuración de subd e unha carga determinada sobre o subd: o subd procesa transaccións por segundo.

É dicir, ao desplegarse, débense realizar os seguintes pasos múltiples dentro da función de fitness:

  1. Procesando o vector de entrada de números - converténdoo en valores para os parámetros de subdatos.
  2. Un intento de crear un número determinado de grupos de refacer dun tamaño determinado. Ademais, o intento pode ser infructuoso.
    Grupos de revistas que xa existían no subd, nalgunha cantidade e dalgún tamaño, pola pureza do experimento - d.b. eliminado.
  3. Se o punto anterior ten éxito: especificando os valores dos parámetros de configuración na base de datos (de novo: pode haber un fallo)
  4. Se o paso anterior é exitoso: detendo o subd, iniciando o subd para que os novos valores dos parámetros especificados teñan efecto. (de novo: pode haber un fallo)
  5. Se o paso anterior ten éxito: realice unha proba de carga. obter métricas de subd.
  6. Devolve o subd ao seu estado orixinal, é dicir. eliminar grupos de rexistro adicionais, devolver a configuración orixinal da subdatabase para que funcione.

Código de función 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)
}

Iso. todo o traballo: realizado na función de fitness.

A subrutina ga procesa vectores ou, máis correctamente, cromosomas.
No que, o máis importante para nós é a selección de cromosomas con xenes para os que a función de fitness produce grandes valores.

Este, en esencia, é o proceso de busca do conxunto óptimo de cromosomas utilizando un vector nun espazo de busca N-dimensional.

Moi claro, detallado explicación, con exemplos de código R, o traballo dun algoritmo xenético.

Gustaríame sinalar por separado dous puntos técnicos.

Chamadas auxiliares desde a función evaluate, por exemplo, parar-iniciar, establecer o valor do parámetro subd, realízanse en función cran-r funcións system2

Coa axuda do cal: chámase algún script ou comando bash.

Por exemplo:

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

O segundo punto é a liña, evaluate funcións, gardando un valor métrico específico e o seu vector de sintonización correspondente nun ficheiro de rexistro:

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

Isto é importante, porque a partir desta matriz de datos, será posible obter información adicional sobre cales dos compoñentes do vector de sintonía teñen un efecto maior ou menor sobre o valor métrico.

É dicir: será posible realizar análises de atributos-importamce.

Entón, que pode pasar?

En forma gráfica, se ordena as probas en orde métrica ascendente, a imaxe é a seguinte:

O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización

Algúns datos correspondentes aos valores extremos da métrica:
O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización
Aquí, na captura de pantalla cos resultados, aclararei: os valores do vector de sintonización danse en termos do código da función de fitness, non en termos da lista numérica de parámetros/rangos de valores de parámetros, que se formulou. arriba no texto.

Ben. É moito ou pouco, ~8 mil tps: unha pregunta aparte.
No marco do traballo de laboratorio, esta cifra non é importante, o importante é a dinámica, como cambia este valor.

A dinámica aquí é boa.
É obvio que polo menos un factor inflúe significativamente no valor da métrica, o algoritmo ga, clasificando a través dos vectores cromosómicos: cuberto.
A xulgar pola dinámica bastante vigorosa dos valores da curva, hai polo menos un factor máis que, aínda que significativamente menor, inflúe.

Aquí é onde o necesitas attribute-importance análise para comprender que atributos (ben, neste caso, compoñentes do vector de sintonía) e canto inflúen no valor métrico.
E a partir desta información: comprender que factores se viron afectados polos cambios nos atributos significativos.

carreira attribute-importance posible de diferentes formas.

Para estes efectos, gústame o algoritmo randomForest paquete R do mesmo nome (a documentación)
randomForest, como entendo o seu traballo en xeral e o seu enfoque para avaliar a importancia dos atributos en particular, constrúe un certo modelo da dependencia da variable resposta dos atributos.

No noso caso, a variable resposta é unha métrica obtida da base de datos nas probas de carga: tps;
E os atributos son compoñentes do vector de sintonía.

Entón aquí randomForest avalía a importancia de cada atributo do modelo con dous números: %IncMSE — como a presenza/ausencia deste atributo nun modelo cambia a calidade MSE deste modelo (Erro medio cadrado);

E IncNodePurity é un número que reflicte o ben que, en función dos valores deste atributo, se pode dividir un conxunto de datos con observacións, de xeito que nunha parte hai datos cun valor da métrica que se explica, e na outra con outro valor da métrica.
Ben, é dicir: ata que punto é este un atributo de clasificación (vin a explicación máis clara en lingua rusa en RandomForest aquí).

Código R obreiro-campesino para procesar un conxunto de datos cos resultados das probas de carga:

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

Pode seleccionar directamente os hiperparámetros do algoritmo coas súas mans e, centrándose na calidade do modelo, seleccionar un modelo que cumpra con máis precisión as predicións do conxunto de datos de validación.
Podes escribir algún tipo de función para este traballo (por certo, de novo, usando algún tipo de algoritmo de optimización).

Podes usar o paquete R caret, non o punto é importante.

Como resultado, neste caso, obtense o seguinte resultado para avaliar o grao de importancia dos atributos:

O método científico poke, ou como seleccionar unha configuración de base de datos usando benchmarks e un algoritmo de optimización

Ben. Así, podemos comezar a reflexión global:

  1. Resulta que o máis significativo, nestas condicións de proba, foi o parámetro commit_wait
    Tecnicamente, especifica o modo de execución da operación io de escribir datos redo desde o búfer de rexistro subdb ao grupo de rexistro actual: síncrono ou asíncrono.
    Valor nowait o que resulta nun aumento case vertical e múltiple do valor da métrica tps: trátase da inclusión do modo io asíncrono nos grupos redo.
    Unha pregunta aparte é se deberías facelo ou non nunha base de datos de alimentos. Aquí limítome a afirmar: este é un factor significativo.
  2. É lóxico que o tamaño do búfer de rexistro do subd: resulte ser un factor significativo.
    Canto menor sexa o tamaño do búfer de rexistro, menor será a súa capacidade de almacenamento en búfer, máis veces se desborda e/ou a imposibilidade de asignar unha área libre nel para unha parte dos novos datos redox.
    Isto significa: atrasos asociados coa asignación de espazo no búfer de rexistro e/ou a descarga de datos de refacer a partir deste en grupos de refacer.
    Estes atrasos, por suposto, deberían e afectan ao rendemento da base de datos para as transaccións.
  3. Parámetro db_block_checksum: ben, tamén, en xeral, está claro: o procesamento de transaccións leva á formación de bloques darty na caché do búfer da subdatabase.
    O cal, cando a comprobación das sumas de control dos bloques de datos está activada, a base de datos ten que procesar: calcular estas sumas de comprobación a partir do corpo do bloque de datos, verificalas co que está escrito na cabeceira do bloque de datos: coincide/non coincide.
    Este traballo, de novo, non pode menos que atrasar o procesamento de datos e, en consecuencia, o parámetro e o mecanismo que establece este parámetro resultan significativos.
    É por iso que o vendedor ofrece, na documentación deste parámetro, diferentes valores para el (o parámetro) e sinala que si, haberá un impacto, pero, ben, pode escoller diferentes valores, ata "desactivado" e diferentes impactos.

Ben, unha conclusión global.

O enfoque, en xeral, resulta ser bastante funcional.

Permítese bastante, nas primeiras fases das probas de carga dun determinado sistema de servizo, para seleccionar a súa configuración óptima (sistema) para a carga, non afondar demasiado nos detalles específicos da configuración do sistema para a carga.

Pero non o exclúe por completo, polo menos a nivel de comprensión: o sistema debe ser coñecido sobre os "botóns de axuste" e os rangos de rotación permitidos destes botóns.

O enfoque pode entón atopar relativamente rapidamente a configuración óptima do sistema.
E en función dos resultados das probas, é posible obter información sobre a natureza da relación entre as métricas de rendemento do sistema e os valores dos parámetros de configuración do sistema.

O que, por suposto, debería contribuír á aparición desta profunda comprensión do sistema, do seu funcionamento, polo menos baixo unha determinada carga.

Na práctica, trátase dun intercambio dos custos de comprensión do sistema personalizado polos custos de preparación de tales probas do sistema.

Gustaríame sinalar por separado: neste enfoque, o grao de adecuación das probas do sistema ás condicións de funcionamento que terá na operación comercial é de vital importancia.

Grazas pola túa atención e tempo.

Fonte: www.habr.com

Engadir un comentario