PostgreSQL Main

หน้าหลัก PostgreSQL

Topic: 

debian: ติดตั้ง slony1 บน etch และ lenny เบื้องต้น

ติดตั้ง slony1 บน etch และ lenny เบื้องต้น

slony เป็นแพ็กเกจส่วนขยายของ PostgreSQL ที่ใช้ทำหน้าที่สำเนาฐานข้อมูลปัจจุบันขณะ แบบใช้ตัวแม่และตัวลูก (master to multiple slaves replication system)
เหมาะสำหรับงานที่ต้องกระจายการทำงาน คืออ่านจากตัวลูกหลายตัว เขียนที่ตัวแม่ตัวเดียว
หรืองานที่ต้องการสำรองข้อมูลแบบปัจจุบันขณะ

ข้อจำกัดของ slony คือ รุ่นของโปรแกรมในการรัน ต้องเป็นรุ่นเดียวกันทั้งตัวแม่และตัวลูก ดังนั้นจึงไม่สามารถใช้แพกเกจของเดเบียนเองได้ เราจึงต้องมาคอมไพล์เอง เพราะเราติดตั้งบนเครื่องที่ต่างรุ่นกัน
และเนื่องจากหาเอกสารที่สมบูรณ์ยาก ในข้อเขียนนี้จึงเป็นเพียงแค่การเริ่มต้นให้ slony ทำงานได้เท่านั้น ยังต้องการปรับตั้งอีกมากที่จะทำให้สามารถใช้งานได้จริง

ข้อควรรู้

  • slony ทำงานแบบ 1 ตัวแม่ หลายตัวลูก เราสามารถอ่านได้ทั้งจากตัวแม่และตัวลูก แต่จะเขียนได้ที่ตัวแม่อย่างเดียว (แต่เขาบอกว่าสามารถทำให้ตัวลูกแทนตัวแม่ได้ด้วย ในกรณีที่ตัวแม่ขัดข้อง และสามารถกลับสู่สภาพเดิมได้ ถ้าตัวแม่กลับขึ้นมาอีกครั้ง แต่ต้องศึกษาเพิ่ม, ถ้ามีเครื่อง 3 เครื่องขึ้นไป มีคนทำให้เป็นตัวแม่ตัวลูกแบบวนรอบได้ ทำให้ได้ระบบที่เหมือนมีตัวแม่ได้หลายตัว แต่เปลืองพลังการทำงาน)
  • โปรแกรมที่ใช้ตั้งค่าเริ่มต้นระบบ ชื่อ slonik ใช้รันที่ตัวแม่อย่างเดียว และโปรแกรมที่ทำงานสำเนาเป็นเบื้องหลังชื่อ slon ตัองสั่งรันทั้งตัวแม่และตัวลูก
  • cluster คือการตั้งชื่อกลุ่มคอมพิวเตอร์ที่เกี่ยวข้องในงานสำเนา 1 งาน ซึ่งจะประกอบด้วย node คือคอมพิวเตอร์และฐานข้อมูลแต่ละชุด และ node จะประกอบด้วย table คือตารางที่เราต้องการคัดลอก ทั้งหมดนี้เราจะต้องนำไปเขียนเป็นข้อกำหนดให้โปรแกรม slonik ทำงาน
  • slony ใช้หลักการทำงาน โดยสร้าง trigger ที่ฐานข้อมูลที่เราจะสำเนา โดยทำในระดับตาราง และมีข้อแม้ว่า ตารางที่ต้องการสำเนา ต้องมี Primary Key ด้วย แต่ถ้าหากไม่มี Primary Key เราตัองแจ้งไว้ในส่วนตั้งข้อกำหนด แล้ว slony ก็จะสร้าง Primary Key ขึ้นมาในตารางของเรา
    ดังนั้นฐานข้อมูลเราจะถูกปรับเปลี่ยนโดย slony ใน 2 จุด คือ 1. เพิ่ม trigger ในแต่ละตารางที่ต้องการสำเนา และ 2. สร้าง Primary Key ในตารางที่ยังไม่มี

รายละเอียดในการทดสอบ คือ

  • ติดตั้งบน etch ใช้เป็นตัวแม่ และบน lenny ใช้เป็นตัวลูก
  • ใช้กับ PostgreSQL รุ่น 8.3 และ slony รุ่น slony-1 1.2.15
  • ตัวอย่างที่ใช้ ปรับปรุงจากตัวอย่างในไฟล์ซอร์สของ slony (ไฟล์ชื่อ SAMPLE)

เริ่มงาน

1 ติดตั้งแพกเกจ และคอมไพล์

ทำเฉพาะที่ตัวแม่ etch
จะปรับรุ่น postgresql ให้เป็น 8.3 เพราะมันเร็วกว่า 8.1 เยอะ จึงต้องใช้บริการของ Debian Backports
ขั้นตอนคือ แก้ /etc/apt/sources.list เพิ่ม backports
# vi /etc/apt/sources.list
...
deb http://www.backports.org/debian etch-backports main contrib non-free
...
ทำทั้งตัวแม่และตัวลูก
ขั้นตอนคือสั่งอัปเดต ติดตั้งแพกเกจ ดาวน์โหลด slony และคอมไพล์
# aptitude update
# aptitude install postgresql-8.3 postgresql-8.3-slony1 postgresql-contrib-8.3 postgresql-server-dev-8.3 build-essential byacc flex
# cd
# mkdir slony
# cd slony
# wget http://slony.info/downloads/1.2/source/slony1-1.2.15.tar.bz2
# tar xfj slony1-1.2.15.tar.bz2
# cd slony1-1.2.15
# ./configure --prefix=/usr/local/slony1-1.2.9
# make
# make install    # (uninstall with make uninstall)

2. ปรับแต่ง postgresql

ทำทั้งตัวแม่และตัวลูก
ตั้งให้สามารถติดต่อได้จากเครื่องอื่น
# vi /etc/postgresql/8.3/main/postgresql.conf
...
listen_addresses = '*'
...

ปรับตั้งผู้ใช้ (แต่งกันเองนะครับ อันนี้เป็นเพียงตัวอย่าง)

# vi /etc/postgresql/8.3/main/pg_hba.conf
...
# "local" is for Unix domain socket connections only
local   all         all                               md5
# IPv4 local connections:
host    all         all         127.0.0.1/32          md5
host    all         all         192.168.0.0/16        md5
# IPv6 local connections:
host    all         all         ::1/128               md5
...

เริ่มการทำงานใหม่

# /etc/init.d/postgresql-8.3 restart

3. ปรับตั้ง slony ตอนเริ่มระบบ

ทำที่ตัวแม่
จะทำงานด้วยผู้ใช้ชื่อ postgres โดยใช้วิธีสร้างสคริปต์ เพื่อให้สะดวกในการปรับแต่ง
3.1 เตรียมการสร้างไดเรกทอรี่
# su postgres
$ cd
$ mkdir slony-script
$ cd slony-script

หมายเหตุ หากต้องการเปลี่ยนผู้ใช้เป็นคนอื่น ควรสร้างไฟล์รหัสผ่านของ postgres ไว้ในไดเรกทอรี่บ้านของตัวเอง ทั้งนี้เพื่อไม่ให้โปแกรมขึ้นมาถามรหัสผ่านตอนรัน ไฟล์รหัสผ่านนี้ ต้องมีชื่อว่า ~/.pgpass มีรูปแบบเป็น HOSTNAME:PORT:DATABASE:USERNAME:PASSWORD และต้องมีข้ออนุญาตเป็น 600 เท่านั้น

3.2 โปรแกรมเก็บตัวแปร ใช้เพื่อกันข้อผิดพลาด จึงทำแยกไว้ เพื่อให้โปรแกรมอื่นมาเรียกใช้ ตั้งชื่อว่า variable.sh ข้อกำหนดเบื้องต้นต่าง ๆ สามารถอ่านจากตัวแปรในโค๊ดได้เลย

$ vi variable.sh
#!/bin/bash
#*** WARNING ***
#   All dabase name DBNAME1 and DBNAME2 will be deleted and replaced by this script. ***

CLUSTER=test_cluster             #CLUSTER NAME
DBNAME1=test                        #DB OF MASTER
DBNAME2=test                        #SLAVE DB
HOST1=master.example.com   #MASTER MACHINE NAME
HOST2=slave.example.com      #SLAVE MACHINE NAME
SLONY_USER=postgres           #SUPERUSER
NORMAL_USER=user1             #NORMAL USER
$ chmod 700 variable.sh

ข้อควรระวัง ห้ามตั้งชื่อเครื่องเป็น localhost เพราะข้อมูลต้องถูกส่งผ่านไปมาระหว่างเครื่องแม่กับเครื่องลูก จะเกิดความสับสนได้ ต้องใช้ชื่อจริงของเครื่อง

3.3 โปรแกรมเตรียมฐานข้อมูล และคัดลอกโครงสร้างไปยังเครื่องลูก ตั้งชื่อว่า slony-prepare.sh
โปรแกรมนี้ดัดแปลงตามใจชอบ สำคัญอยู่แค่ บรรทัดเอาตัวแปรจาก variable.sh กับ 2 บรรทัดสุดท้าย

$ vi slony-prepare.sh
#!/bin/bash

. ./variable.sh

#*** WARNING ***
#   All dabase name DBNAME1 and DBNAME2 will be deleted and replaced by this script. ***

echo "$HOST1 task"
#create db to replicate at master
dropdb -U $SLONY_USER -h $HOST1 $DBNAME1
createdb -U $SLONY_USER -O $NORMAL_USER -h $HOST1 $DBNAME1
createlang -U $SLONY_USER -h $HOST1 plpgsql $DBNAME1

psql -U $SLONY_USER $DBNAME1 <<EOF
    CREATE TABLE accounts (
        aid     SERIAL,
        name    VARCHAR(50),
        address VARCHAR(255)
    );
    INSERT INTO accounts (name, address) VALUES ('account1','address1');

    CREATE TABLE branches (
        bid     SERIAL,
        name    VARCHAR(50),
        address VARCHAR(255)
    );
    INSERT INTO branches (name, address) VALUES ('branch1','address2');

    CREATE TABLE tellers (
        tid     SERIAL,
        name    VARCHAR(50),
        address VARCHAR(255)
    );
    INSERT INTO tellers (name, address) VALUES ('tellers1','address3');

    CREATE TABLE history (
        session VARCHAR(50),
        detail  VARCHAR(255)
    );
    INSERT INTO history (session, detail) VALUES ('xxxx','detail1');
EOF

#...

echo "$HOST2 task"

#drop old db at slave
dropdb -U $SLONY_USER -h $HOST2 $DBNAME2

#create db at slave
createdb -U $SLONY_USER -O $NORMAL_USER -h $HOST2 $DBNAME2

#copy structure from master to slave
pg_dump -s -U $SLONY_USER -h $HOST1 $DBNAME1 | psql -U $SLONY_USER -h $HOST2 $DBNAME2
$ chmod 700 slony-prepare.sh
$ ./slony-prepare.sh

3.4 โปรแกรมสร้างเซ็ตให้ slony บรรจุข้อกำหนดของคลัสเตอร์ โหนด และตารางที่จะทำการคัดลอก
ตั้งชื่อว่า slony-setup.sh

$ vi slony-setup.sh
#!/bin/bash

. ./variable.sh

slonik <<_EOF_ 
    # ----
    # This defines which namespace the replication system uses
    # ----
    cluster name = $CLUSTER;

    # ----
    # Admin conninfo's are used by the slonik program to connect
    # to the node databases.  So these are the PQconnectdb arguments
    # that connect from the administrators workstation (where
    # slonik is executed).
    # ----
    node 1 admin conninfo = 'dbname=$DBNAME1 host=$HOST1 user=$SLONY_USER';
    node 2 admin conninfo = 'dbname=$DBNAME2 host=$HOST2 user=$SLONY_USER';
    
    # ----
    # Initialize the first node.  The id must be 1.
    # This creates the schema "_test1" containing all replication
    # system specific database objects.
    # ----
    init cluster ( id = 1, comment = 'Node 1' );

    # ----
    # The pgbench table history does not have a primary key or
    # any other unique constraint that could be used to identify
    # a row.  The following command adds a bigint column named
    # "_Slony-I_test1_rowID" to the table.  It will have a default
    # value of nextval('"_test1".sl_rowid_seq'), be unique and not
    # null.  All existing rows will be initialized with a number.
    # ----
    table add key ( node id = 1, fully qualified name = 'public.history' );   

    # ----
    # The Slony replication system organizes tables in sets.  The
    # smallest unit another node can subscribe is a set.  Usually the
    # tables contained in one set would be all tables that have
    # relationships to each other.  The following commands create
    # one set containing all 4 pgbench tables.  The "master" or origin
    # of the set is node 1.
    # ----
    create set ( id = 1, origin = 1, comment = 'All pgbench tables' );
    set add table ( set id = 1, origin = 1,
        id = 1, fully qualified name = 'public.accounts',
        comment = 'Table accounts' );
    set add table ( set id = 1, origin = 1,
        id = 2, fully qualified name = 'public.branches',
        comment = 'Table branches' );
    set add table ( set id = 1, origin = 1,
        id = 3, fully qualified name = 'public.tellers',
        comment = 'Table tellers' );
    set add table ( set id = 1, origin = 1,
        id = 4, fully qualified name = 'public.history',
        key = serial,
        comment = 'Table history' );

    # ----
    # Create the second node, tell the two nodes how to connect to
    # each other and that they should listen for events on each
    # other.  Note that these conninfo arguments are used by the
    # slon daemon on node 1 to connect to the database of node 2
    # and vice versa.  So if the replication system is supposed to
    # use a separate backbone network between the database servers,
    # this is the place to tell it.
    # ----
    store node ( id = 2, comment = 'Node 2' );
    store path ( server = 1, client = 2,
        conninfo = 'dbname=$DBNAME1 host=$HOST1 user=$SLONY_USER');
    store path ( server = 2, client = 1,
        conninfo = 'dbname=$DBNAME2 host=$HOST2 user=$SLONY_USER');
    store listen ( origin = 1, provider = 1, receiver = 2 );
    store listen ( origin = 2, provider = 2, receiver = 1 );
_EOF_
$ chmod 700 slony-setup.sh
$ ./slony-setup.sh

หมายเหตุ บันทึกกันลืม ใน slony1 รุ่น 2.X ขึ้นไป ไม่ต้องใช้คำสั่ง table add key สำหรับตารางที่ไม่มี Primary Key แล้ว

ทำที่ตัวลูก
จะทำงานด้วยผู้ใช้ชื่อ postgres เหมือนกัน

3.5 เตรียมการสร้างไดเรกทอรี่

# su postgres
$ cd
$ mkdir slony-script
$ cd slony-script

3.6 โปรแกรมเก็บตัวแปร (กันข้อผิดพลาด)

$ vi variable.sh
#!/bin/bash
#*** WARNING ***
#   All dabase name DBNAME1 and DBNAME2 will be deleted and replaced by this script. ***

CLUSTER=test_cluster             #CLUSTER NAME
DBNAME1=test                        #DB OF MASTER
DBNAME2=test                        #SLAVE DB
HOST1=master.example.com   #MASTER MACHINE NAME
HOST2=slave.example.com      #SLAVE MACHINE NAME
SLONY_USER=postgres           #SUPERUSER
NORMAL_USER=user1             #NORMAL USER
$ chmod 700 variable.sh

4. สั่งเตรียมคัดลอก

ทำที่ตัวแม่
สั่งรันโปรแกรมในการส่งข้อมูลคัดลอก โดยต้องรันค้างไว้ (ในการใช้งานจริง ควรทำสคริปต์ไว้เป็นการทำงานเบื้องหลัง
$ . ./variable.sh
$ slon $CLUSTER "dbname=$DBNAME1 user=$SLONY_USER"

จะมีข้อความรายงานออกมามากมายเป็นปกติ

ทำที่ตัวลูก
สั่งรันโปรแกรมในการรับข้อมูลคัดลอก ต้องรันค้างไว้เหมือนกัน
$ . ./variable.sh
$ slon $CLUSTER "dbname=$DBNAME2 user=$SLONY_USER"

ถึงตอนนี้ ฐานข้อมูลของทั้งสองโหนด พร้อมที่คัดลอกไปสู่กันแล้ว แต่ยังไม่มีการคัดลอกจริง ๆ เราต้องสั่ง subscribe เซ็ตที่เราสร้างขึ้นในหัวข้อ 3 ในหัวข้อถัดไป

5. สั่งให้ทำการคัดลอกตามเซ็ตที่กำหนด (subscribe)

ทำที่ตัวแม่อย่างเดียว
สร้างสคริปต์สำหรับ subscribe ตั้งชื่อว่า slony-subscribe.sh
$ vi slony-subscribe.sh
#!/bin/bash

. ./variable.sh

slonik <<_EOF_
    # ----
    # This defines which namespace the replication system uses
    # ----
    cluster name = $CLUSTER;

    # ----
    # Admin conninfo's are used by the slonik program to connect
    # to the node databases.  So these are the PQconnectdb arguments
    # that connect from the administrators workstation (where
    # slonik is executed).
    # ----
    node 1 admin conninfo = 'dbname=$DBNAME1 host=$HOST1 user=$SLONY_USER';
    node 2 admin conninfo = 'dbname=$DBNAME2 host=$HOST2 user=$SLONY_USER';

    # ----
    # Node 2 subscribes set 1
    # ----
    subscribe set ( id = 1, provider = 1, receiver = 2, forward = no);
_EOF_
$ chmod 700 slony-subscribe.sh
$ ./slony-subscribe.sh

ถึงตอนนี้ slony จะทำการคัดลอกฐานข้อมูล ใช้เวลาแป๊ปเดียวก็เสร็จ เพราะข้อมูลเรามีนิดเดียว (แหล่งที่มาบอกว่า ฐานข้อมูลขนาด 30G ใช้เวลา 4 ชั่วโมง)

จบแล้วครับ

การศึกษาต่อไปคือ ให้ทดลองติดตั้งแพกเกจ slony1-bin และ slony1-doc ของเดเบียน และศึกษาการทำงานของสคริปต์ในแพกเกจนั้น ในการทำให้โปรแกรมทำงานเป็นเบื้องหลัง และสั่ง subscribe หรือ unsubscribe ให้สะดวกมากขึ้น

เอามาจาก

postgresql: เชื่อมต่อจาก VFP

บันทึกการเชื่อมต่อฐานข้อมูล PostgreSQL จาก Visual Foxpro
เนื่องจากต้องการเอาข้อมูลเก่าใน VFP เข้ามาเก็บใน PostgreSQL

ขั้นตอนมีดังนี้

ดาวน์โหลดไดรฟ์เวอร์จาก GBorg: spsqlODBC Downloads
และติดตั้งให้เรียบร้อย

ติดตั้ง Data Source ในวินโดวส์ผ่าน Control panel -> ODBC Data Sources โดยป้อนชื่อฐานข้อมูลและชื่อผู้ใช้ให้เรียบร้อย

เชื่อมต่อจาก vfp ด้วยคำสั่ง
conn = SQLSTRINGCONNECT([Driver={PostgreSQL Unicode};Server=127.0.0.1;Port=5432;Database=persoane;Uid=postgres;Pwd=123456])

ตัวอย่าง
conn = SQLSTRINGCONNECT([Driver={PostgreSQL Unicode};Server=192.168.1.1;Port=5432;Database=mydata;Uid=wd;Pwd=wdpassword])
SQLEXEC(conn, "SELECT * FROM mytable WHERE myfield='condition'")
sele sqlresult
brow

ยังมีปัญหาเรื่องฟิลด์ TEXT ไปเป็น Memo ทำความยาวได้ไม่เกิน 256 อักขระ
อีกอันนึงคือเรื่อง LF ในลินุกซ์ และ CR+LF ในวินโดวส์

อ้างอิง
PostgreSQL: i can't connect to postgresql with VFP 8