Окт. 142012
 

This post is also available in: English

Добре, де. Сървъра не е хилав. Обаче не е и някакво чудо неземно. Все пак е Dev сървър, на него търкаляме Dev бази.

Проблемът е, че търкаляме 30 Dev бази на един сървър. Вярно, във всеки един момент активно работят само 5-6 от тях (или 1-2). Но не и като дойде време за събиране на статистики. Настъпи ли време за събиране на статистики… жална му майка на сървъра. Всичките 30 бази почват да въртят дисковете – въртят, сумтят… и дисковете клякат. ASM също кляка и понякога дори спира да respond-ва за няколко секунди. В екстремните случаи се случва няколко бази да загинат:

ORA-15064: communication failure with ASM instance
ORA-03113: end-of-file on communication channel
Process ID:
Session ID: 4 Serial number: 1
ASMB (ospid: 8290): terminating the instance due to error 15064

Тук е времето да уточня, че тези 30 бази се създават като копия на една „master“ база. Каквото има на нея – такова има на тях. Всеки developer или екип може да си пресъздаде базата като текущо копие на master базата, или, много по-рядко, като копие на базата на другарчето си. Така че ако на master базата пише статистиките да тръгнат в 22:00 часа, рано или късно всички други бази ще започнат да си събират статистики в 22:00. И това, всъщност, е най-най-тежкото нещо, което може да се случи на този сървър.

Ето и решението, което съчиних:

create or replace procedure p_scramble_stats_start as
  v_start_hour char(1);
  v_start_min char(2);
BEGIN
  -- disable
  DBMS_SCHEDULER.DISABLE(name => '"SYS"."MONDAY_WINDOW"', force => TRUE);
  DBMS_SCHEDULER.DISABLE(name => '"SYS"."TUESDAY_WINDOW"', force => TRUE);
  DBMS_SCHEDULER.DISABLE(name => '"SYS"."WEDNESDAY_WINDOW"', force => TRUE);
  DBMS_SCHEDULER.DISABLE(name => '"SYS"."THURSDAY_WINDOW"', force => TRUE);
  DBMS_SCHEDULER.DISABLE(name => '"SYS"."FRIDAY_WINDOW"', force => TRUE);
  DBMS_SCHEDULER.DISABLE(name => '"SYS"."SATURDAY_WINDOW"', force => TRUE);
  DBMS_SCHEDULER.DISABLE(name => '"SYS"."SUNDAY_WINDOW"', force => TRUE);
  -- "choose" the time
  select to_char(ora_hash(instance_name, 6)), to_char(ora_hash(instance_name, 59))
    into v_start_hour, v_start_min
    from v$instance;
  -- set
  DBMS_SCHEDULER.SET_ATTRIBUTE(name      => '"SYS"."MONDAY_WINDOW"',
                               attribute => 'REPEAT_INTERVAL',
                               value     => 'freq=daily;byday=MON;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0');
  DBMS_SCHEDULER.SET_ATTRIBUTE(name      => '"SYS"."TUESDAY_WINDOW"',
                               attribute => 'REPEAT_INTERVAL',
                               value     => 'freq=daily;byday=TUE;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0');
  DBMS_SCHEDULER.SET_ATTRIBUTE(name      => '"SYS"."WEDNESDAY_WINDOW"',
                               attribute => 'REPEAT_INTERVAL',
                               value     => 'freq=daily;byday=WED;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0');
  DBMS_SCHEDULER.SET_ATTRIBUTE(name      => '"SYS"."THURSDAY_WINDOW"',
                               attribute => 'REPEAT_INTERVAL',
                               value     => 'freq=daily;byday=THU;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0');
  DBMS_SCHEDULER.SET_ATTRIBUTE(name      => '"SYS"."FRIDAY_WINDOW"',
                               attribute => 'REPEAT_INTERVAL',
                               value     => 'freq=daily;byday=FRI;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0');
  DBMS_SCHEDULER.SET_ATTRIBUTE(name      => '"SYS"."SATURDAY_WINDOW"',
                               attribute => 'REPEAT_INTERVAL',
                               value     => 'freq=daily;byday=SAT;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0');
  DBMS_SCHEDULER.SET_ATTRIBUTE(name      => '"SYS"."SUNDAY_WINDOW"',
                               attribute => 'REPEAT_INTERVAL',
                               value     => 'freq=daily;byday=SUN;byhour='||v_start_hour||';byminute='||v_start_min||';bysecond=0');
  -- enable
  DBMS_SCHEDULER.ENABLE(name => '"SYS"."MONDAY_WINDOW"');
  DBMS_SCHEDULER.ENABLE(name => '"SYS"."TUESDAY_WINDOW"');
  DBMS_SCHEDULER.ENABLE(name => '"SYS"."WEDNESDAY_WINDOW"');
  DBMS_SCHEDULER.ENABLE(name => '"SYS"."THURSDAY_WINDOW"');
  DBMS_SCHEDULER.ENABLE(name => '"SYS"."FRIDAY_WINDOW"');
  DBMS_SCHEDULER.ENABLE(name => '"SYS"."SATURDAY_WINDOW"');
  DBMS_SCHEDULER.ENABLE(name => '"SYS"."SUNDAY_WINDOW"');
END;

Тази процедура си избира произволен час и минута (от 00:00 до 6:59) на база името на инстанса. След това сетва всичките maintenance прозорци (в които се събират статистики) да се отварят в този час. В нашия случай събирането продължава от 5 до 15 минути на база, така че не е проблем.

Направих на всички бази един job, който всяка вечер в 22:00 да изпълнява тази процедура. Така който и да копира от master или от някой друг, ще бъде фикснат най-късно на следващата вечер.

И от тогава не сме имали такива проблеми.

 Posted by at 9:23

Sorry, the comment form is closed at this time.