суббота, 1 ноября 2014 г.

алгоритм разруливания ситуации split brain в Oracle RAC

каков алгоритм разруливания ситуации split brain в Oracle RAC, сценарии такие:
1) порвались все interconnects
2) погиб vote disk
3) 1+2
4) один из двух узлов Oracle RAC намертво завис, а через какое-то время отвис
вообщем если в 8 нодовом кластере 3 ноды отвалятся и получится что сервера останутся в рахных группах 3 в одной и 2 в другой то та группа с 3 нодам даст сигнал той группе из двух нод отключится 

Алгоритмы там простые как японский самурай - все узлы кроме нулевого сделают себе харакири.

Вообще оракловые решения отличаются склонностью к самоубийствам (даже простой ASM на одном узле в 10.2.0.4), а уж кластерные (что RAC что OCFSv2) особенно.

Кстати, ИНТЕРКОННЕКТ там один - насколько я помню, ни в одном кластере оракла не было возможности описывать несколько.

В случае 4 - узел пришибется процессом oprocd если тот оживет (что не факт). До версии 10.2.0.3 - модулем hangcheck_timer.

Ну что там зависит? Если нет внешнего фенсинга и есть ровно ОДИН интерконнект и абсолютно дубовый алгоритм принятия решения (что в OCFSv2 что в СRS)? При любом чихе вся конструкция говорит _АЙ-ЯЙ-ЯЙ, я не знаю что делать, а потому лучше я сделаю себе харакири_ и перевызывает систему без единого, подчеркну без единого, слова в логах! (oprocd этим особо славится). 

При этом реализация оного oprocd во первых толком не документирована (там какие то гистограммы и прочая лапша наворочены), а во вторых просто як сибирский валенок
- запускаем процесс
- вешаем в нем приоритет RT
- засыпляем, по просыплянию проверяем насколько он отстал
- если отстал больше чем на маржин то убиваем систему мгновенно и безболезненно (причем так чтобы она вообще ничего не успела сделать)

Авторы свято верили в то, что RT процесс самый приоритетный (что НЕ ПРАВДА АБОСЛЮТНО), в то что не бывает задержек вызванных скажем виртуализацией (в итоге OPROCD приходится выключать в VMware нафиг), а также в то, что харакири нужно делать ВСЕГДА (даже когда система не имеет в данный момент никаких ресурсов взятых у кластера). В итоге сразу же была выдана рекомендация ставить там один загадочный параметр в 13 - вычитая из 13 3 получаем 10 секунд марджина вместо 500 миллисекунд по умолчанию.

Ну и все прочее в ораклиных кластерах в том же духа - святая вера в правду бумажки без попытки подумать сначала что получится. В итоге получается нечто, падающее при проблемах оборудования направо и налево (и к тому же не фига не отрабатывающее частичные проблемы). И толку от оного oprocd немного, потому что по жизни процессы ядра ПРИОРИТЕТНЕЕ чем процесс oprocd и скажем если зациклится драйвер а потом отциклится - то сначала система отработает задержавшиеся обмены скажем в iSCSI или в FC HBA (тем самым успешно развалив диски) а потом уже проснувшийся oprocd вонзит в нее карающий меч...

Если сравнивать с нормальными кластерами, то ораклиные - просто детский лепет начинающих индусов.


четверг, 9 октября 2014 г.

Раздуваем таблицы и пожираем tablespaces

Раздуваем таблицы и пожираем tablespaces из песочницы


Картинка для придания нужного настроения

Доброго времени суток!


В интернете вообще и на Хабре в частности немало публикаций о ремонте битых блоков. Например, здесь о выдергивании неповрежденных данных, а тут история победы над битым LOB сегментом.

Приводить легионы ссылок на инет с подобными статьями не буду. Но есть в большинстве этих статей общая черта. Когда данные спасены (или уничтожены, как получится), предлагается победить поврежденный free block захватом всего свободного места в tablespace. И почему то это предложение описательно.

Так добавим конкретики!

Напишем скрипт, который скушает (почти как рыбки на картинке), а потом освободит всё свободное место Oracle DB.

Подготовительная часть.

Посмотрели на наши битые блоки:
select * from v$database_block_corruption;

Убедились, что они есть.

Посмотрели точно ли все наши блоки «free»(вдруг еще один сломанный сегмент затерялся?):
SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file#
     , greatest(e.block_id, c.block#) corr_start_block#
     , least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block#
     , least(e.block_id+e.blocks-1, c.block#+c.blocks-1) 
       - greatest(e.block_id, c.block#) + 1 blocks_corrupted
     , null description
  FROM dba_extents e, v$database_block_corruption c
 WHERE e.file_id = c.file#
   AND e.block_id <= c.block# + c.blocks - 1
   AND e.block_id + e.blocks - 1 >= c.block#
UNION
SELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file#
     , header_block corr_start_block#
     , header_block corr_end_block#
     , 1 blocks_corrupted
     , 'Segment Header' description
  FROM dba_segments s, v$database_block_corruption c
 WHERE s.header_file = c.file#
   AND s.header_block between c.block# and c.block# + c.blocks - 1
UNION
SELECT null owner, null segment_type, null segment_name, null partition_name, c.file#
     , greatest(f.block_id, c.block#) corr_start_block#
     , least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block#
     , least(f.block_id+f.blocks-1, c.block#+c.blocks-1) 
       - greatest(f.block_id, c.block#) + 1 blocks_corrupted
     , 'Free Block' description
  FROM dba_free_space f, v$database_block_corruption c
 WHERE f.file_id = c.file#
   AND f.block_id <= c.block# + c.blocks - 1
   AND f.block_id + f.blocks - 1 >= c.block#
order by file#, corr_start_block#;


Не забудем отключить autoextend для всех файлов нашего TS с битыми free блоками. Последствия забывчивости могут оказаться не очень приятными.
Да, «сжать» файлы обратно можно успеть. Но зачем нам лишние проблемы?
select 
    'alter database datafile '||
    file_name||
    ' '||
    ' autoextend off;'
from 
    dba_data_files where TABLESPACE_NAME='PSAPSR3';

Получили список команд. Запустили их. Потом таким же образом сформируем список команд, которые вернут autoextend.
Но здесь надо быть внимательным. Может датафайлы располагаются на разных дисках? И у них разные настройки расширения? Здесь стоит быть аккуратнее.

(Да, моя специальность «Специалист SAP BASIS». Этим и объясняется выбор имени для tablespace. Ведь ошибки я вынужден чинить именно там.)

И только теперь, когда подготовительные шаги завершены.

Основная часть

Для работы с Oracle sql я использую SQL Developer. В нем есть все что нужно, и не наблюдается того, что не нужно.

Чего мы хотим?
Переформатировать все свободные блоки tablespace. Для этого будем создавать таблицы, и добавлять им экстенты пока место не закончится.

Вот такой скриптик PL\SQL нормально делает то, что нам нужно.
SET SERVEROUTPUT ON
DECLARE
type ARR_TABLE is table of varchar2(13);
TBLS ARR_TABLE:=ARR_TABLE();
I number;
SPACE_AVAILABLE float;
--Константа с целевым tablespace
TABLESPACE_FOR_FULL CONSTANT varchar2(20) := 'PSAPSR3';
--Константа со схемой. Почему бы нет?
USER_SCHEMA CONSTANT varchar2(20) := 'SAPSR3';

--Вычисляем свободное место в TS
function TABLESPACE_FREESIZE(TN varchar2) return number
as si number; 
begin
  SELECT round(sum(bytes)/1048576,2) into si from DBA_FREE_SPACE where TABLESPACE_NAME = TN;
  return SI;
end TABLESPACE_FREESIZE;

--Создание и раздувание очередной таблицы пока не выскочит ora-1653
procedure create_new_tables as
  N number;
  I number;
  UNABLE_TO_EXTEND EXCEPTION;
  PRAGMA EXCEPTION_INIT(UNABLE_TO_EXTEND,-1653);
BEGIN
  N:=TBLS.COUNT;
  N:=N+1;
  TBLS.extend;
  TBLS(N):='TESTTABLE'||N;
  execute immediate 'create table '||USER_SCHEMA||'.'||TBLS(n)||\' (id number(10), USER_NAME varchar2(10), CREATE_DATE date) tablespace '||TABLESPACE_FOR_FULL;
   WHILE true LOOP
    begin
      execute immediate 'alter table '||USER_SCHEMA||'.'||TBLS(n)||' allocate extent';
      EXCEPTION
      when UNABLE_TO_EXTEND then
      EXIT;
    end;
  END LOOP;
 end create_new_tables;

BEGIN
--Подготовка
  DBMS_OUTPUT.PUT_LINE( 'Time start: '||TO_CHAR(sysdate,  'DD-MM-YYYY HH24:MI:SS'));
  SPACE_AVAILABLE:=TABLESPACE_FREESIZE(TABLESPACE_FOR_FULL);
  DBMS_OUTPUT.PUT_LINE('Space available='||SPACE_AVAILABLE);

--Запуск 
  WHILE SPACE_AVAILABLE>0.001 LOOP
    CREATE_NEW_TABLES();
    SPACE_AVAILABLE:=TABLESPACE_FREESIZE(TABLESPACE_FOR_FULL);
--Когда функция TABLESPACE_FREESIZE начнет выдавать NULL вместо числа - цикл остановится.
  end LOOP;

--Очистка созданных таблиц
  for I in 1..TBLS.COUNT LOOP
    execute immediate 'drop table '||USER_SCHEMA||\'.'||TBLS(I);
  end LOOP;
  DBMS_OUTPUT.PUT_LINE( 'Time end: '||TO_CHAR(sysdate,  'DD-MM-YYYY HH24:MI:SS'));
end;

(Прошу обратить внимание на два лишних слеша "\". В строках с «create table» и «drop table». Они для того, чтобы выделение цветом не ехало. Перед боевым использованием их надо снести. А менять кавычки на другие я не хочу. Очень раздражает последующее выискивание «неверных».)

Опять же, заданные константы TABLESPACE_FOR_FULL и USER_SCHEMA как бы намекают на специфику моих баз.
Комментировать алгоритм работы мне видится излишним.

Скорость работы такой методы меня устраивает.

anonymous block completed
Time start: 22-10-2013 13:10:10
Space available=827,88
Time end: 22-10-2013 13:10:11

anonymous block completed
Time start: 22-10-2013 13:10:27
Space available=10668,75
Time end: 22-10-2013 13:10:46

anonymous block completed
Time start: 22-10-2013 13:11:26
Space available=99266,81
Time end: 22-10-2013 13:14:37


Чуть менее 100Gb за 3 минуты. Ясно, что оборудование играет очень большую роль, но там где оборудование слабое и размеров особых не будет. Тем более что Tb свободного места достаточно странная ситуация.

Завершающие шаги

Теперь вернув autoextend можно заняться проверкой базы.

rman target /

И
BACKUP VALIDATE database;


После чего представление v$database_block_corruption должно быть чистым как… ну вы поняли.

Эпилог

А есть ли способ короче и быстрее? Должен быть. Обязательно. Я начал писать на PL\SQL три недели назад. И в первую очередь я специалист SAP BASIS, а не DBA.
Мне вполне хватает и этого. Но было бы интересно посмотреть на решение этой задачи от профи.

Как избавиться от ORA-01410, вычленив неповрежденные данные

Как избавиться от ORA-01410, вычленив неповрежденные данные из песочницы

Одно время серьезно набил руку вот на какой задаче — по ряду таблиц в результате компрессии и ораклового бага побились несколько строк. В результате чего пользователи при фулскане по таким таблиц получали ORA-01410.
Рассмотрим самый тяжелый случай — когда нет ни бэкапов, ни индексов (в этом случае проиндексированные колонки можно получить при сканировании по индексу). В данном случае единственный вариант — найти проблемный ROWID и «обогнуть» его с двух сторон, вычленив неповрежденные данные.

Для начала снимем трейс по проблемному запросу, для того чтобы получить исходные данные:
alter session set db_file_multiblock_read_count=1;
alter session set events 'immediate trace name trace_buffer_on level 1048576';
alter session set events '10200 trace name context forever, level 1';
alter session set events '1410 trace name errorstack forever, level 10';
alter session set tracefile_identifier='ORA1410';


и запускаем проблемный запрос
select count(1) from test.testtable;

Находим в трейсе запись вроде этой:
ktrget2(): started for block  <0x0645 : 0x3ce2c85b> objd: 0x00f842bb
env: (scn: 0x0a21.9a61c1d8  xid: 0x0000.000.00000000  uba: 0x00000000.0000.00  statement num=0  parent xid: xid: 0x0000.000.00000000  scn: 0x0000.00000000 96sch: scn: 0x0000.00000000  mascn: (scn: 0x0a1f.ccec0b27)
OBJD MISMATCH typ=6, seg.obj=16270011, diskobj=16268354, dsflg=100001, dsobj=16270011, tid=16270011, cls=1


По полученному значению получаем Block_number и Relative_fno:
select dbms_utility.data_block_address_file(to_number('3ce2c85b', 'xxxxxxxx')) file#,
dbms_utility.data_block_address_block(to_number('3ce2c85b', 'xxxxxxxx')) block# from dual;

FILE# BLOCK#
243 2279515


Дополнительно находим data_object_id проблемного объекта:
select data_object_id  from dba_objects   where owner = 'test'   and object_name = 'testtable';
 data_object_id
----------------------
16402245


По полученным значениям формируем ROWID:
select dbms_rowid.rowid_create(rowid_type => 1,object_number =>  16402245,relative_fno => 243,block_number => 2279515,row_number => 0) from dual;

ROWID=AA+kdFADzAAIshbAAA

Ну и, собственно, то, о чем я упоминал вначале — огибаем проблемную строку со всех сторон:
insert into test.testtable_nocorrupt 
select /*parallel(8)*/ * from test.testtable 
where rowid<'AA+EK7ADzAAIshbAAA';

insert into test.testtable_nocorrupt 
select /*parallel(8)*/ * from test.testtable
where rowid>='AA+EK7ADzAAIshcAAA';


Хотелось бы отметить, что подобных проблем, скорее всего, удалось бы избежать, имея выставленные параметры БД db_block_checking/db_block_checksum = 'Full' или db_ultra_safe = 'data_and_index', что несколько нагрузило бы процессор (~5%, хотя это обсуждаемо), но дало бы дополнительную надежность.

Используемые ноты Металинка:
Extracting Data from a Corrupt Table using ROWID Range Scans in Oracle8 and higher [ID 61685.1]
OERR: ORA-8103 «object no longer exists» / Troubleshooting, Diagnostic and Solution [ID 8103.1]

Восстановление битых блоков в Oracle — LOB сегмент

Восстановление битых блоков в Oracle — LOB сегмент из песочницы

В один прекрасный момент в алерт-логе очень большой БД, начали появляться сообщения следующего содержания:
Corrupt block relative dba: 0x0724c078 (file 28, block 2408568)
Fractured block found during backing up datafile
Reread of blocknum=2408568, file=E:\ORACLE\ORADATA\XXX\XXX_BLOB16.DBF. found same corrupt data

Ситуация осложнялось тем, что бэкапов под рукой не было.
Далее последуют инструкции по выходу из данной ситуации.


RMAN упирался в данный блок и ни в какую не хотел бэкапить базу.
Начался детальный разбор полетов, и выяснение к чему относится данный блок:
SELECT owner, segment_name, segment_type 
FROM dba_extents 
WHERE file_id = 28 
AND 2408568 BETWEEN block_id AND block_id + blocks - 1;

OWNER
----------------------------
SEGMENT_NAME
----------------------------
SEGMENT_TYPE
------------------
DOC_USER
SYS_LOB0000075021C00003$$
LOBSEGMENT

Далее было выяснено к какой таблице относился данный LOB сегмент:
SELECT table_name, column_name 
          FROM dba_lobs 
         WHERE owner='DOC_USER'
           AND segment_name='SYS_LOB0000075021C00003$$';

TABLE_NAME
-------------------
COLUMN_NAME
-------------------
DOC_LARGE_PIC
BINARY_DATA

DBMS_REPAIR — не смог прояснить ситуации, ввиду ограничений на работу с LOB полями.

На просторах сети было найдено решение — суть его заключалась в следующем:
  • 1. Поочередно перебрать записи из таблицы.
  • 2. При попадании в запись, относящейся к битому блоку выдернуть ее ROWID.


set serverout on
        exec dbms_output.enable(100000);
        declare
         error_1578 exception;
         pragma exception_init(error_1578,-1578);
         n number;
         cnt number:=0;
         badcnt number:=0;
        begin
          for cursor_lob in
                (select rowid r, BINARY_DATA L from DOC_USER.DOC_LARGE_PIC)
          loop
            begin
              n:=dbms_lob.instr(cursor_lob.L,hextoraw('AA25889911'),1,999999) ;
            exception
             when error_1578 then
               dbms_output.put_line('Got ORA-1578 reading LOB at '||cursor_lob.R);
               badcnt:=badcnt+1;
            end;
            cnt:=cnt+1;

          end loop;
          dbms_output.put_line('Scanned '||cnt||' rows - saw '||badcnt||' errors');
        end;
        /


Скрипт успешно вернул две записи:

Got ORA-1578 reading LOB at AAASUNAAQAAPf7hAAY
Got ORA-1578 reading LOB at AAASUNAAQAAPf7hAAp


При помощи нехитрого запроса были получены PRIMARY KEY данных записей и записи были успешно потерты.

Казалось бы, вот оно решение проблемы — но RMAN упорно не хотел резервировать базу упираясь в данные блоки.
Запрос в V$DATABASE_BLOCK_CORRUPTION и RMAN VALIDATE DATAFILE подтвердили о том, что блоки остались в прежнем состоянии.

Не очень хотелось создавать таблицу и забивать ее под завязку всего табличного пространства, поэтому было принято решение использовать ALTER TABLE XXX SHRINK SPACE.

ALTER TABLE DOC_USER.DOC_LARGE_PIC ENABLE ROW MOVEMENT;
ALTER TABLE DOC_USER.DOC_LARGE_PIC SHRINK SPACE CASCADE;


Затем запускаем проверку проблемного файла RMAN'ом:
RMAN VALIDATE DATAFILE 28;

После данной операции представление V$DATABASE_BLOCK_CORRUPTION оказалось кристально чистым.
Далее база была успешно зарезервирована RMAN'ом а недостающие записи были выдернуты из реплики.

UPDATE

Данная проблема возникла после того как начали рассыпаться диски на сервере.
Копию раздела сняли сторонней утилитой и развернули на новый свежесобранный массив.
Все операции проводились на базе весом 1,5 Тб.
Вес таблицы 70 Гб.
Версия Oracle 11g R2 — думаю данный способ применим и для 10g.
ALTER TABLE… SHRINK SPACE CASCADE имеет ряд ограничений предварительно рекомендую ознакомится сдокументацией перед его использованием.
+5
3645
22
proger89 1,0

суббота, 4 октября 2014 г.

Перенесли базу ORACLE, содержащую в том числе
OWB repository, на другой сервер путем полного экспорта-импорта.
(Сказано, что OWB встроен в ORACLE 11, поэтому на сервер больше ничего , кроме ORACLE,
не ставили )
При попытке законнетится владельцем workspace в Design Center возникает ошибка
API502-Cannot connect to the specified account.
Verify connection information.
Хотя законнектится этим пользователем к базе посредством sql/plus
удается.
Удается также зайти через Repository Assistant, который вызывается по кнопке
Workspace Management окна Design Center Logon и посмотреть языки и пользователей. 
ORACLE 11.1 Enterprise Edition, OWB Repository 11.1.0.1, OWB Client 11.1.0.6
Что нужно сделать? Помогите, пожалуйста.

> Перенесли базу ORACLE, содержащую в том числе
> OWB repository, на другой сервер путем полного экспорта-импорта.
Уверен, что полного экспорта-импорта? (это может оказаться ключевым моментом)
На Металинке есть нота под такую операцию (называется как-то How to update OWB after database cloning)

Или порыщи на Oracle-овом OWB-ешном форуме (надо как минимум выполнить update табличек OWBRTPS, WB_RT_SERVICE_NODES - для обновления пути к Oracle home и )

Да вроде как жил там же - все в одном флаконе, на одном сервере.

По ноте дошли до
* Update the Location Credentials stored in the Control Center

1. Start the OWB Browser Listener.

1. For Warehouse Builder 10.2:

For Windows : Start -> Programs -> Oracle OWB 10.2 -> Warehouse Builder -> Administration -> Start OWB Browser Listener
For Linux : OWB_home/owb/bin/unix/startOwbbInst.sh

2. For Warehouse Builder 11.1:

See the steps in Note 469422.1 : How To Start The Warehouse Builder 11g Repository Browser Listener

2. Start the Repository Browser.
For Windows : Start -> Programs -> Oracle -> Warehouse Builder -> Repository Browser
For Linux : OWB_home/owb/bin/unix/openRAB.sh

Repository Browser can be started from the client for unsupported platform.


3. Connect to Warehouse Builder Browser as the Control Center Owner.
И тут - ошибка
Not a valid Warehouse Builder Control Center

были инвалиды в OWF_MGR
осталось два, идут ссылки на несущуствующий
WF_ALL_JOBS. Синоним есть, объекта самого нет.
В исходной базе этот объект есть под SYS - это view.
Причем все остальные объекты WF_ в старой базе - под 
OWF_MGR (кроме PUBLIC SYNONYM)
Почему это так?

Ну еще при неполном экспорте проекта (например на уровне модуля) OWB будет включать в список зависимые объекты из других модулей.
Типичный пример - в мэппинге используется таблица другого модуля, без опции "export dependencies" таблицы другого модуля не будут экспортированы

подскажите, плз, а как очистить хранилище?
Там один workspace, пытаюсь удалить его с клиента:
вызываю Design Center, там с его окна логина кнопкой Workspace Management
вызываю Repository Assistent, далее он спрашивает инфу для коннекта, 
потом выбрать , что делать - Create/Delete Workspace, Manage Users, Add languages,
выбираю операции над workspace, далее - Drop, далее - Workspace Owner (OWB), Workspace name
(он там только один - OWB.OWB) и кнопка Finish.
В итоге появляется ошибка
ORA-20003: WBSecurityHelper found the SQL error:ORA-01927: cannot REVOKE privileges you did not grant

> Перенесли базу ORACLE, содержащую в том числе
> OWB repository, на другой сервер путем полного экспорта-импорта.
Уверен, что полного экспорта-импорта? (это может оказаться ключевым моментом)
На Металинке есть нота под такую операцию (называется как-то How to update OWB after database cloning)

Или порыщи на Oracle-овом OWB-ешном форуме (надо как минимум выполнить update табличек OWBRTPS, WB_RT_SERVICE_NODES - для обновления пути к Oracle home и )