Główne cechy Bucardo to:
- Asynchroniczna kaskadowa replikacja master-slave i/lub master-master
- Replikacja typy 'row based'
- W swoim działania używa triggerów i asynchronicznych powiadomień LISTEN/NOTIFY/UNLISTEN (link do poprzedniego postu na ten temat tutaj)
- Wymaga dedykowanej bazy danych. Działa jako demon programu napisanego w Perlu, który komunikuje się ze swoją bazą danych i wszystkimi innymi bazami związanymi z działającymi replikacjami (synchronizacjami)
- Multimaster synchronizacja jest ograniczona tylko do dwóch baz danych (Od wersji 5.0 to ograniczenie już nie istnieje). Dla tego typu replikacji musi być zdefiniowany sposób rozwiązywania konfliktów. Typy definicji ich rozwiązywania:
- source - wiersz na bazy 'source' zawsze wygrywa
- target - wiersz na bazie 'target' zawsze wygrywa
- skip - wiersze przy, których wynikł konflikt nie są zreplikowane
- random - każdy z serwerów ma takie same szanse
- latest - wiersz, który został niedawno zmieniony, wygrywa
- abort - synchronizacja jest przerywana na konflikt
- Replikacja master-slave umożliwia działanie jednego mastera z wieloma slavami
- Jest możliwa kaskadowa synchronizacja
- Nie ma możliwości replikacji zmian typu DDL ponieważ PostgreSQL nie ma triggerów na tabelach systemowych
- Nie ma możliwości replikacji dużych obiektów
- Możliwość dowolnego projektowania architektury naszej replikacji
- Wymagania:
- PostgreSQL:
- Od wersji 8.X
- zainstalowany język pl/perlu
- zainstalowany język pl/pgsl
- Perl + moduły (DBD::Pg, DBI, DBIx::Safe, ExtUtils::MakeMaker)
- Bucardo w wersji 4 trzeba zdefiniować jeden z typów synchronizacji:
- fullcopy - master - slave bez konieczności definiowania klucza głównego na tabeli (http://bucardo.org/wiki/Fullcopy)
- pushdelt - master - slave (http://bucardo.org/wiki/Pushdelta)
- swap - master-master (http://bucardo.org/wiki/Swap)
Od wersji 5.0 definiujemy tylko tabele źródłowe "source" (master) i docelowe "target" (slave) - nie definiujemy już typu synchronizacji - Demony działające w Bucardo:
- MCP - Master Control Process - główny proces zarządzający synchronizującymi
- CTL - Controller - śledzi i zabija procesy synchronizujące
- KID - Proces synchronizujący
- Bardzo prosta instalacja paczek perl-owych i Bucardo:
perl Makefile.pl make make test sudo make install
Instalacja Bucardo:
[bucardo@bucardo ~]$ /usr/local/bin/bucardo install This will install the bucardo database into an existing Postgres cluster. Postgres must have been compiled with Perl support, and you must connect as a superuser Current connection settings: 1. Host:
2. Port: 5432 3. User: postgres 4. Database: bucardo 5. PID directory: /var/run/bucardo Enter a number to change it, P to proceed, or Q to quit: 3 Change the user to: bucardo Changed user to: bucardo Current connection settings: 1. Host: 2. Port: 5432 3. User: bucardo 4. Database: bucardo 5. PID directory: /var/run/bucardo Enter a number to change it, P to proceed, or Q to quit: 4 Change the database name to: test Changed database name to: test Current connection settings: 1. Host: 2. Port: 5432 3. User: bucardo 4. Database: test 5. PID directory: /var/run/bucardo Enter a number to change it, P to proceed, or Q to quit: P Postgres version is: 9.3 Attempting to create and populate the bucardo database and schema Database creation is complete Updated configuration setting "piddir" Installation is now complete. If you see errors or need help, please email bucardo-general@bucardo.org You may want to check over the configuration variables next, by running: /usr/local/bin/bucardo show all Change any setting by using: /usr/local/bin/bucardo set foo=bar - Konfiguracja Bucardo
- Przykład dodania bazy danych
[bucardo@bucardo ~]$ /usr/local/bin/bucardo add database amsterdam dbname=test host=188.226.xxx.xxx user=root pass=root Added database "amsterdam" [bucardo@bucardo ~]$ /usr/local/bin/bucardo add database niujork dbname=test host=107.170.xx.xx user=root pass=root Added database "niujork"
- Przykład listy baz danych
[bucardo@bucardo ~]$ /usr/local/bin/bucardo list dbs Database: amsterdam Status: active Conn: psql -U root -d test -h 188.226.xxx.xxx Database: niujork Status: active Conn: psql -U root -d test -h 107.170.xx.xx
- Przykład dodania tabeli
[bucardo@bucardo ~]$ /usr/local/bin/bucardo add table test1 db=amsterdam Added the following tables or sequences: public.test1 [bucardo@bucardo ~]$ /usr/local/bin/bucardo add table test1 db=niujork Added the following tables or sequences: public.test1
- Przykład usuwania tabel
[bucardo@bucardo ~]$ /usr/local/bin/bucardo remove table test1 Please use the full schema.table name [bucardo@bucardo ~]$ /usr/local/bin/bucardo remove table public.test1 Removed the following tables: public.test1 [bucardo@bucardo ~]$ /usr/local/bin/bucardo list tables No tables have been added yet
- Przykład stworzenia synchronizacji
[bucardo@bucardo ~]$ /usr/local/bin/bucardo add sync test1_sync dbs=niujork,amsterdam tables=test1 conflict_strategy=bucardo_source WARNING: Issuing rollback() due to DESTROY without explicit disconnect() of DBD::Pg::db handle dbname=test;host=107.170.39.26 at line 279. KONTEKST: PL/Perl function "validate_sync" SQL statement "SELECT validate_sync('test1_sync')" PL/Perl function "validate_sync" Failed to add sync: DBD::Pg::st execute failed: ERROR: DBD::Pg::db do failed: ERROR: permission denied for database test at line 280. at line 30. KONTEKST: PL/Perl function "validate_sync" at /usr/local/bin/bucardo line 4413.
W bazach musi być zainstalowany język plperl:
test=> CREATE EXTENSION plperl; CREATE EXTENSION test=> \dL Lista języków Nazwa | Właściciel | Zaufany | Opis ---------+------------+---------+------------------------------ plperl | root | t | PL/Perl procedural language plpgsql | postgres | t | PL/pgSQL procedural language (2 wiersze) test=> \q
Stworzenie synchronizacji typu master-slave (pierwsza baza jest typu 'source', a druga (albo po prostu każde następne) 'target'):
[bucardo@bucardo ~]$ /usr/local/bin/bucardo add sync test1_sync dbs=niujork,amsterdam tables=test1 conflict_strategy=bucardo_source Added sync "test1_sync" Created a new relgroup named "test1_sync" Created a new dbgroup named "test1_sync"
Stworzenie synchronizacji typu master-master (jawnie definiujemy typ bazy danych):
[bucardo@bucardo ~]$ /usr/local/bin/bucardo add sync test1_sync dbs=niujork:source,amsterdam:source tables=test1 conflict_strategy=bucardo_source Added sync "test1_sync" Created a new relgroup named "test1_sync" Created a new dbgroup named "test1_sync_2"
- Status synchronizacji
[bucardo@bucardo ~]$ /usr/local/bin/bucardo status PID of Bucardo MCP: 22761 Name State Last good Time Last I/D Last bad Time ============+========+============+=========+===========+===========+======= test1_sync | Good | 11:06:44 | 24m 32s | 0/373 | none |
Szczegółowe informacje o synchronizacji:
[bucardo@bucardo ~]$ /usr/local/bin/bucardo status test1_sync ====================================================================== Last good : Aug 12, 2014 11:06:43 (time to run: 2s) Rows deleted/inserted : 0 / 373 Sync name : test1_sync Current state : Good Source relgroup/database : test1_sync / amsterdam Tables in sync : 1 Status : Active Check time : None Overdue time : 00:00:00 Expired time : 00:00:00 Stayalive/Kidsalive : Yes / Yes Rebuild index : No Autokick : Yes Onetimecopy : No Post-copy analyze : Yes Last error: : ======================================================================
Każda tabela w synchronizacji ma nałożone na sobie triggery. Oto przykładowa tabela:
test=# \d test1 Tabela "public.test1" Kolumna | Typ | Modyfikatory ---------+-----------------------+------------------------------------------------------ c1 | integer | niepusty domyślnie nextval('test1_c1_seq'::regclass) c2 | character varying(20) | c3 | integer | Indeksy: "test1_pkey" PRIMARY KEY, btree (c1) Wyzwalacze: bucardo_delta AFTER INSERT OR DELETE OR UPDATE ON test1 FOR EACH ROW EXECUTE PROCEDURE bucardo.delta_public_test1() bucardo_kick_test1_sync AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON test1 FOR EACH STATEMENT EXECUTE PROCEDURE bucardo.bucardo_kick_test1_sync() bucardo_note_trunc_test1_sync AFTER TRUNCATE ON test1 FOR EACH STATEMENT EXECUTE PROCEDURE bucardo.bucardo_note_truncation('test1_sync')
Triggery:
- bucardo.delta_public_test1 - wywołuje inserty z kluczem głównym 'zmienionego' wiersza do tabeli trakującej delta_public_test1
BEGIN IF (TG_OP = 'INSERT') THEN INSERT INTO bucardo.delta_public_test1 VALUES (NEW."c1"); ELSIF (TG_OP = 'UPDATE') THEN INSERT INTO bucardo.delta_public_test1 VALUES (OLD."c1"); IF (OLD."c1" <> NEW."c1") THEN INSERT INTO bucardo.delta_public_test1 VALUES (NEW."c1"); END IF; ELSE INSERT INTO bucardo.delta_public_test1 VALUES (OLD."c1"); END IF; RETURN NULL; END;
- bucardo.bucardo_kick_test1_sync - wywołanie NOTIFY do bucardo informując, że doszło do zmian.
BEGIN EXECUTE $nn$NOTIFY bucardo, 'kick_sync_test1_sync'$nn$; RETURN NEW; END;
- bucardo.bucardo_note_truncation - wywołuje insert do tabeli trakującej, informując o wykonaniu polecenia TRUCATE. Czyści także tabele trakujące zmiany
Od wersji 5.0 dane zanim będą przeniesione do docelowego serwera, są usuwane (przy conflict_stategy = 'bucardo_source') przy pomocy klucza głównego, aby za pobiedź konfliktom danych. W wcześniejszej wersji były najpierw sprawdzane pojedynczo, co powodowało obciążenie serwera i bardzo duże opóźnienia.
DELETE FROM public.test1 WHERE c1 = ANY('{{"5"}}')
Przenoszenie danych:
COPY (SELECT * FROM public.test1 WHERE c1 IN ('6')) TO STDOUT COPY public.test1("c1","c2","c3") FROM STDIN
Zdecydowanie polecam obecną wersje tego programu do replikacji danych zwłaszcza z powodu lepszej wydajności. Jeśli jednak potrzebujemy tylko replikacji typu master-slave wybrała bym wbudowaną replikację PostgreSQLa bo działa na poziomie plików binarnych i nie obciąża serwera dodatkowymi zapytaniami.