INT 21h

Hi, I am Vladimir Smagin, SysAdmin and Kaptain. Telegram Email / GIT / Thingiverse / RSS / GPG

Логическая репликация в Postgresql

№ 11067 В разделе "Sysadmin" от July 10th, 2020,
В подшивках: , ,

Чтобы полностью понять принцип работы логической репликации нужно прочитать документацию. Если кратко, то логическая репликация передает не бинарные данные, а запросы INSERT, UPDATE, DELETE или их сочетание, что позволяет тонко управлять реплицируемыми данными, а также делать это между разными мажорными версиями СУБД. В моем случае я буду мигрировать с 10й версии на 12ю с маленьким даунтаймом. Вся концепция репликации строится на публикациях изменений и подписках, причем подписчик сам может публиковать данные уже для своих подписчиков.

На реплицируемой базе данных необходимо создать публикатор:

postgres=# \c zabbix 
You are now connected to database "zabbix" as user "postgres".
zabbix=# CREATE PUBLICATION zbx FOR ALL TABLES;
CREATE PUBLICATION

Не забываем в postgresql.conf поставить параметр wal_level = logical. Теперь можно сдампить текущую схему БД в файл, который позже будет залит в целевую БД.

postgres@boroda:/tmp$ pg_dump -h 127.0.0.1 -p 5432 -s zabbix > zabbix_schema.sql

Для уверенности можно проверить состояние публикатора

zabbix=# \dRp
                          List of publications
 Name |  Owner   | All tables | Inserts | Updates | Deletes | Truncates 
------+----------+------------+---------+---------+---------+-----------
 zbx  | postgres | t          | t       | t       | t       | t
(1 row)

А теперь на целевом сервере создадим новую базу, зальем схему и подпишемся на источник данных:

postgres=# create database zabbix;
CREATE DATABASE
postgres=# create role zabbix;
CREATE ROLE

А вот теперь можно и залить схему в новую БД:

postgres@boroda:/tmp$ cat /tmp/zabbix_schema.sql | psql -p 5434 zabbix

Ну вот и пришло время заливаться

postgres=# \c zabbix 
You are now connected to database "zabbix" as user "postgres".
zabbix=# CREATE SUBSCRIPTION zbx CONNECTION 'postgresql://postgres:postgres@127.0.0.1:5432/zabbix' PUBLICATION zbx WITH (slot_name=zbx_slot);
NOTICE:  created replication slot "zbx_slot" on publisher
CREATE SUBSCRIPTION

По умолчанию данные будут автоматически скопированы, но с помощью WITH можно изменить поведение подписки. Обратите внимание, что под репликацию лучше создать отдельного пользователя и ограничить ему доступ по IP в pg_hba.conf, но т.к. оба моих сервера находятся в безопасной среде мне на это пофигу и я копирую данные прямо суперюзером.

Проверим состояние подписки:

zabbix=# \dRs
          List of subscriptions
 Name |  Owner   | Enabled | Publication 
------+----------+---------+-------------
 zbx  | postgres | t       | {zbx}
(1 row)

Проверим начали ли данные передаваться:

zabbix=# select count(*) from hosts;
 count 
-------
    53
(1 row)

Все выглядит просто ништяк, данные перекачались в новое место, теперь можно переключать Zabbix со старой базы данных на новую, а потом просто дропнуть подписку.

Не забудьте перестроить индексы мигрировавшей базы данных:

zabbix=# reindex database CONCURRENTLY zabbix;

Нет комментариев »

Сломался Postgresql

№ 11057 В разделе "Sysadmin" от June 29th, 2020,
В подшивках: ,

После жеского ребута сервера одним менеджером несмотря на многократное “никогда так не перезагружай сервер” сломалась БД.

sql> SELECT id, phone, url, pid, ip, ref, created, addtime FROM cc_phones WHERE idcampaign = '1891' AND pid not in ('6b6', 'fbf') AND addtime >= '2020-06-26 10:00' AND sent=False
[2020-06-29 16:41:44] [XX002] ERROR: index "cc_phones_addtime_idcampaign_index" contains unexpected zero page at block 266946
[2020-06-29 16:41:44] Подсказка: Please REINDEX it.

Жопа. Нужно сделать новые индексы и скорее всего совсем не одной таблицы, это долго.

farm=# reindex table cc_phones;
WARNING: concurrent insert in progress within table "cc_phones"
ERROR: could not access status of transaction 2885466886
DETAIL: Could not read from file "pg_subtrans/ABFC" at offset 188416: Success.
CONTEXT: while checking uniqueness of tuple (1217807,2) in relation "cc_phones"

Решилось созданием пустого файла pg_subtrans/ABFC из файла рядом, который также забит нулями.

Нет комментариев »

GlusterFS as shared disk between computers

№ 11038 В разделе "Sysadmin" от June 25th, 2020,
В подшивках:

You working at home and have 2 or more computers with file server somewhere in basement? Samba is an answer to your needs, but I know you want to do some

Typically GlusterFS used in clusters with many nodes to provide stability and high speed but we made it as single node installation with many clients.

Add repository https://launchpad.net/~gluster/+archive/ubuntu/glusterfs-7 and install glusterfs-server to your home server, glusterfs-client to all client machines. Be sure hostname boroda (or whatever your server is called) added to your local DNS server.

On server create directory for files, I made /srv/glusterfs-shit

Time to gluster volume create shit boroda:/srv/glusterfs-shit force

Disable trash for your shit gluster volume set shit features.trash off

Allow local clients to connect gluster volume set shit auth.allow 192.168.1.0/24

Start u’r shit:

gluster volume start shit
gluster volume status shit

On clients you already installed client software, so just mount new volume:

mkdir /media/shit
sudo chown vlad:vlad /media/shit -R
sudo mount.glusterfs boroda:/shit /media/shit
sudo chown vlad:vlad /media/shit -R

Now try to save something and check it on all installed machines.

Make it permanent

echo 'boroda:/shit /media/shit glusterfs defaults,_netdev 0 0' | sudo tee -a /etc/fstab

Нет комментариев »

Centralize fail2ban blacklisting with ip-blocker-db

№ 11031 В разделе "Sysadmin" от June 17th, 2020,
В подшивках: ,

My own IP storage for fail2ban. Written to blacklist fucking botnets bruteforcing my servers. It centalize information about blocks across all my servers in one single watch tower.

https://git.blindage.org/21h/ip-blocker-db

Нет комментариев »

Golang: marshal and unmarshal iota (yaml, json, toml)

№ 11025 В разделе "Programming" от June 16th, 2020,
В подшивках:

Tried to unmarshal enum value from app config file and failed?

DB:
  masterDB: "ips.sdb"
  clean: Full

Use strings instead of iota.

const (
	CleanRecreate  = "Recreate" // completely remove DB file and create again
	CleanFull      = "Full" // delete all and vacuum
	CleanLastDay   = "LastDay" // remove all before last day
	CleanLastWeek  = "LastWeek"
	CleanLastMonth = "LastMonth"
	CleanNever     = "Never" // do nothing
)

type CleanType string

type AppConfig struct {
	DB    struct {
		MasterDB string    `yaml:"masterDB"`        // master sqlite database
		Clean    CleanType `yaml:"clean,omitempty"` // cleanup at startup
	} `yaml:"DB"`
}

Now load config file:

func main() {
	flag.Parse()
	if *configFilename == "" {
		log.Fatalln("Set configuration filename")
	}

	// read settings from file
	log.Println("Loading config file", *configFilename)
	appConfig := AppConfig{}

	yamlFile, err := ioutil.ReadFile(*configFilename)
	if err != nil {
		log.Fatalf("Config read error: %v\n", err)
	}
	err = yaml.Unmarshal(yamlFile, &appConfig)
	if err != nil {
		log.Fatalf("Config format error: %v\n", err)
	}

	switch appConfig.DB.Clean {
	case CleanRecreate:
		log.Println("Recreate cleanup option set")
		os.Remove(appConfig.DB.MasterDB)
	case CleanFull:
		log.Println("Full cleanup option set")
	case CleanLastDay:
		log.Println("Save only last day cleanup option set")
	case CleanLastWeek:
		log.Println("Save only last week option set")
	case CleanLastMonth:
		log.Println("Save only last month option set")
	}
	dbHandler := dbLoadFile(appConfig.DB.MasterDB)
	defer dbHandler.Close()
}

Here is another solution https://gist.github.com/lummie/7f5c237a17853c031a57277371528e87#file-enum-go

Нет комментариев »

Яндекс.Метрика

Fortune cookie: The three most important parts of a stove: lifter, leg, and poker.