ื”ื™ื›ืจื•ืช ืขื ืžืขืจื›ืช ื”ื’ื™ื‘ื•ื™ wal-g PostgreSQL

WAL-G ื”ื•ื ื›ืœื™ ืคืฉื•ื˜ ื•ื™ืขื™ืœ ืœื’ื™ื‘ื•ื™ PostgreSQL ืœืขื ื ื™ื. ืžื‘ื—ื™ื ืช ื”ืคื•ื ืงืฆื™ื•ื ืœื™ื•ืช ื”ืขื™ืงืจื™ืช ืฉืœื•, ื”ื•ื ื”ื™ื•ืจืฉ ืฉืœ ื”ื›ืœื™ ื”ืคื•ืคื•ืœืจื™ WAL-E, ืื‘ืœ ื ื›ืชื‘ ืžื—ื“ืฉ ื‘-Go. ืื‘ืœ ื™ืฉ ืชื›ื•ื ื” ื—ื“ืฉื” ื•ื—ืฉื•ื‘ื” ื‘-WAL-G - ืขื•ืชืงื™ ื“ืœืชื. ืขื•ืชืงื™ ื“ืœืชื WAL-G ืœืื—ืกืŸ ื“ืคื™ ืงื‘ืฆื™ื ืฉื”ืฉืชื ื• ืžืื– ื’ืจืกืช ื”ื’ื™ื‘ื•ื™ ื”ืงื•ื“ืžืช. WAL-G ืžื™ื™ืฉืžืช ืœื ืžืขื˜ ื˜ื›ื ื•ืœื•ื’ื™ื•ืช ืœื’ื™ื‘ื•ื™ื™ื ืžืงื‘ื™ืœื™ื. WAL-G ืžื”ื™ืจ ื‘ื”ืจื‘ื” ืž-WAL-E.

ืคืจื˜ื™ื ืขืœ ืื™ืš wal-g ืขื•ื‘ื“ ื ื™ืชืŸ ืœืžืฆื•ื ื‘ืžืืžืจ: ืื ื—ื ื• ืขื•ืฉื™ื ืื•ื‘ืจclock ืœื’ื™ื‘ื•ื™. ื”ืจืฆืื” ืฉืœ Yandex

ืคืจื•ื˜ื•ืงื•ืœ ื”ืื—ืกื•ืŸ S3 ื”ืคืš ืคื•ืคื•ืœืจื™ ืœืื—ืกื•ืŸ ื ืชื•ื ื™ื. ืื—ื“ ื”ื™ืชืจื•ื ื•ืช ืฉืœ S3 ื”ื•ื ื™ื›ื•ืœืช ื”ื’ื™ืฉื” ื‘ืืžืฆืขื•ืช API, ื”ืžืืคืฉืจืช ืœืืจื’ืŸ ืื™ื ื˜ืจืืงืฆื™ื” ื’ืžื™ืฉื” ืขื ื”ืื—ืกื•ืŸ, ื›ื•ืœืœ ื’ื™ืฉืช ืงืจื™ืื” ืฆื™ื‘ื•ืจื™ืช, ื‘ืขื•ื“ ืฉืขื“ื›ื•ืŸ ื”ืžื™ื“ืข ื‘ืื—ืกื•ืŸ ืžืชืจื—ืฉ ืจืง ืขืœ ื™ื“ื™ ืื ืฉื™ื ืžื•ืจืฉื™ื.

ื™ืฉื ื ืžืกืคืจ ื™ื™ืฉื•ืžื™ื ืฆื™ื‘ื•ืจื™ื™ื ื•ืคืจื˜ื™ื™ื ืฉืœ ืื—ืกื•ืŸ ื”ืคื•ืขืœื™ื ืขืœ ืคืจื•ื˜ื•ืงื•ืœ S3. ื”ื™ื•ื ื ื‘ื—ืŸ ืคืชืจื•ืŸ ืคื•ืคื•ืœืจื™ ืœืืจื’ื•ืŸ ืื—ืกื•ืŸ ืงื˜ืŸ - Minio.

ืฉืจืช PostgreSQL ื™ื—ื™ื“ ืžืชืื™ื ืœื‘ื“ื™ืงืช wal-g, ื•-Minio ืžืฉืžืฉ ื›ืชื—ืœื™ืฃ ืœ-S3.

ืฉืจืช ืžื™ื ื™ื•

ื”ืชืงื ืช ืžื™ื ื™ื•

yum -y install yum-plugin-copr
yum copr enable -y lkiesow/minio
yum install -y minio

ืขืจื•ืš ืืช AccessKey ื•ืืช SecretKey ื‘-/etc/minio/minio.conf

vi /etc/minio/minio.conf

ืื ืœื ืชืฉืชืžืฉ ื‘-nginx ืœืคื ื™ Minio, ืื– ืืชื” ืฆืจื™ืš ืœืฉื ื•ืช

--address 127.0.0.1:9000

--address 0.0.0.0:9000

ืžืฉื™ืงื” ืืช Minio

systemctl start minio

ืขื‘ื•ืจ ืืœ ืžืžืฉืง ื”ืื™ื ื˜ืจื ื˜ ืฉืœ Minio http://ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-minio:9000 ื•ืœื™ืฆื•ืจ ื“ืœื™ (ืœื“ื•ื’ืžื”, pg-backups).

ืฉืจืช DB

WAL-G ื‘ืกืœ"ื“ ืžื•ืจื›ื‘ ืขืœ ื™ื“ื™ (ืื ื˜ื•ืŸ ืคื˜ืกื‘). GitHub, ืคื“ื•ืจื” COPR.

ืœืžื™ ืฉืื™ืŸ ืžืขืจื›ืช ืžื‘ื•ืกืกืช RPM, ื”ืฉืชืžืฉ ื‘ืจืฉืžื™ืช ื”ื•ืจืื” ืœืคื™ ื”ืชืงื ื”.

ื™ื—ื“ ืขื ื”ื‘ื™ื ืืจื™ wal-g, rpm ืžื›ื™ืœ ืกืงืจื™ืคื˜ื™ื ืฉืžื™ื™ื‘ืื™ื ืžืฉืชื ื™ื ืžื”ืงื•ื‘ืฅ /etc/wal-gd/server-s3.conf.

backup-fetch.sh
backup-list.sh
backup-push.sh
wal-fetch.sh
wal-g-run.sh
wal-push.sh

ื”ืชืงืŸ ืืช wal-g.

yum -y install yum-plugin-copr
yum copr enable -y antonpatsev/wal-g
yum install -y wal-g

ื‘ื•ื“ืง ืืช ื’ืจืกืช wal-g.

wal-g --version
wal-g version v0.2.14

ืขืจื•ืš ืืช /etc/wal-gd/server-s3.conf ืœืฆืจื›ื™ื ืฉืœืš.

ืงื•ื‘ืฆื™ ื”ืชืฆื•ืจื” ื•ืงื‘ืฆื™ ื”ื ืชื•ื ื™ื ื”ืžืฉืžืฉื™ื ืืฉื›ื•ืœ ืžืกื“ ื ืชื•ื ื™ื ืžืื•ื—ืกื ื™ื ื‘ืื•ืคืŸ ืžืกื•ืจืชื™ ื‘ื™ื—ื“ ื‘ืกืคืจื™ื™ืช ื ืชื•ื ื™ ื”ืืฉื›ื•ืœ, ื”ืžื›ื•ื ื” ื‘ื“ืจืš ื›ืœืœ PGDATA

#!/bin/bash

export PG_VER="9.6"

export WALE_S3_PREFIX="s3://pg-backups" # ะฑะฐะบะตั‚, ะบะพั‚ะพั€ั‹ะน ะผั‹ ัะพะทะดะฐะปะธ ะฒ S3
export AWS_ACCESS_KEY_ID="xxxx" # AccessKey ะธะท /etc/minio/minio.conf 
export AWS_ENDPOINT="http://ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-minio:9000"
export AWS_S3_FORCE_PATH_STYLE="true"
export AWS_SECRET_ACCESS_KEY="yyyy" # SecretKey ะธะท /etc/minio/minio.conf

export PGDATA=/var/lib/pgsql/$PG_VER/data/
export PGHOST=/var/run/postgresql/.s.PGSQL.5432 # ะกะพะบะตั‚ ะดะปั ะฟะพะดะบะปัŽั‡ะตะฝะธั ะบ PostgreSQL

export WALG_UPLOAD_CONCURRENCY=2 # ะšะพะป-ะฒะพ ะฟะพั‚ะพะบะพะฒ ะดะปั ะทะฐะบะฐั‡ะบะธ 
export WALG_DOWNLOAD_CONCURRENCY=2 # ะšะพะป-ะฒะพ ะฟะพั‚ะพะบะพะฒ ะดะปั ัะบะฐั‡ะธะฒะฐะฝะธั
export WALG_UPLOAD_DISK_CONCURRENCY=2 # ะšะพะป-ะฒะพ ะฟะพั‚ะพะบะพะฒ ะฝะฐ ะดะธัะบะต ะดะปั ะทะฐะบะฐั‡ะบะธ
export WALG_DELTA_MAX_STEPS=7
export WALG_COMPRESSION_METHOD=brotli # ะšะฐะบะพะน ะผะตั‚ะพะด ัะถะฐั‚ะธั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ.

ื‘ืขืช ื”ื’ื“ืจืช WAL-G, ืืชื” ืžืฆื™ื™ืŸ WALG_DELTA_MAX_STEPS - ืžืกืคืจ ื”ืฆืขื“ื™ื ืฉื’ื™ื‘ื•ื™ ื”ื“ืœืชื ื”ื•ื ื”ืžืงืกื™ืžืœื™ ืžื”ื’ื™ื‘ื•ื™ ื”ื‘ืกื™ืกื™, ื•ืžืฆื™ื™ืŸ ืืช ืžื“ื™ื ื™ื•ืช ื”ืขืชืงืช ื”ื“ืœืชื. ืื• ืฉืืชื” ื™ื•ืฆืจ ืขื•ืชืง ืžื”ื“ืœืชื ื”ืงื™ื™ืžืช ื”ืื—ืจื•ื ื”, ืื• ืฉืืชื” ืขื•ืฉื” ื“ืœืชื ืžื”ื’ื™ื‘ื•ื™ ื”ืžืœื ื”ืžืงื•ืจื™. ื–ื” ื”ื›ืจื—ื™ ื‘ืžืงืจื” ืฉื‘ื• ืื•ืชื• ืจื›ื™ื‘ ืฉืœ ืžืกื“ ื”ื ืชื•ื ื™ื ืชืžื™ื“ ืžืฉืชื ื” ื‘ืžืกื“ ื”ื ืชื•ื ื™ื ืฉืœืš, ืื•ืชื ื ืชื•ื ื™ื ืžืฉืชื ื™ื ื›ืœ ื”ื–ืžืŸ.

ื”ืชืงื ืช ืžืกื“ ื”ื ืชื•ื ื™ื.

yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.
noarch.rpm
yum install -y postgresql96 postgresql96-server mc

ืื ื• ืžืืชื—ืœื™ื ืืช ืžืกื“ ื”ื ืชื•ื ื™ื.

/usr/pgsql-9.6/bin/postgresql96-setup initdb
Initializing database ... OK

ืื ืืชื” ื‘ื•ื“ืง ืขืœ ืฉืจืช ืื—ื“, ืขืœื™ืš ืœื”ื’ื“ื™ืจ ืžื—ื“ืฉ ืืช ื”ืคืจืžื˜ืจ wal_level ืœืืจื›ื™ื•ืŸ ืขื‘ื•ืจ PostgreSQL ืคื—ื•ืช ืžื’ืจืกื” 1, ื•ื”ืขืชืง ืขื‘ื•ืจ PostgreSQL ื’ืจืกื” 10 ื•ืžืขืœื”.

wal_level = archive

ื‘ื•ืื• ื ื’ื‘ื” ืืช ืืจื›ื™ื•ื ื™ WAL ื›ืœ 60 ืฉื ื™ื•ืช ื‘ืืžืฆืขื•ืช PostgreSQL ืขืฆืžื”. ื‘-prod, ื™ื”ื™ื” ืœืš ืขืจืš archive_timeout ืฉื•ื ื”.

archive_mode = on
archive_command = '/usr/local/bin/wal-push.sh %p'
archive_timeout = 60 # ะšะฐะถะดั‹ะต 60 ัะตะบัƒะฝะด ะฑัƒะดะตั‚ ะฒั‹ะฟะพะปะฝัั‚ัั ะบะพะผะฐะฝะดะฐ archive_command.

ื”ืคืขืœืช PostgreSQL

systemctl start postgresql-9.6

ื‘ืžืกื•ืฃ ื ืคืจื“, ืื ื• ืžืกืชื›ืœื™ื ืขืœ ื™ื•ืžื ื™ PostgreSQL ืขื‘ื•ืจ ืฉื’ื™ืื•ืช: (ืฉื ื” ืืช postgresql-Wed.log ืœื–ื” ื”ื ื•ื›ื—ื™).

tail -fn100 /var/lib/pgsql/9.6/data/pg_log/postgresql-Wed.log

ื‘ื•ื ื ืœืš ืœ-psql.

su - postgres
psql

ืฆื•ืจ ืžืกื“ ื ืชื•ื ื™ื ื‘-psql

ืฆื•ืจ ื˜ื‘ืœื” ื‘ืžื‘ื—ืŸ ืžืกื“ ื”ื ืชื•ื ื™ื1.

create database test1;

ืขื‘ื•ืจ ืœืžื‘ื—ืŸ ืžืกื“ ื”ื ืชื•ื ื™ื.

postgres=# c test1;

ืื ื• ื™ื•ืฆืจื™ื ืืช ื”ื˜ื‘ืœื” indexing_table.

test1=# CREATE TABLE indexing_table(created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());

ื”ื•ืกืคืช ื ืชื•ื ื™ื.

ืื ื—ื ื• ืžืชื—ื™ืœื™ื ืœื”ื›ื ื™ืก ื ืชื•ื ื™ื. ืื ื—ื ื• ืžื—ื›ื™ื 10-20 ื“ืงื•ืช.

#!/bin/bash
# postgres
while true; do
psql -U postgres -d test1 -c "INSERT INTO indexing_table(created_at) VALUES (CURRENT_TIMESTAMP);"
sleep 60;
done

ื”ืงืคื“ ืœื‘ืฆืข ื’ื™ื‘ื•ื™ ืžืœื.

su - postgres
/usr/local/bin/backup-push.sh

ืื ื• ืžืกืชื›ืœื™ื ืขืœ ื”ืจืฉื•ืžื•ืช ื‘ื˜ื‘ืœื” ื‘ืžื‘ื—ืŸ ืžืกื“ ื”ื ืชื•ื ื™ื1

select * from indexing_table;
2020-01-29 09:41:25.226198+
2020-01-29 09:42:25.336989+
2020-01-29 09:43:25.356069+
2020-01-29 09:44:25.37381+
2020-01-29 09:45:25.392944+
2020-01-29 09:46:25.412327+
2020-01-29 09:47:25.432564+
2020-01-29 09:48:25.451985+
2020-01-29 09:49:25.472653+
2020-01-29 09:50:25.491974+
2020-01-29 09:51:25.510178+

ื”ืžื—ืจื•ื–ืช ื”ื™ื ื”ืฉืขื” ื”ื ื•ื›ื—ื™ืช.

ืขื™ื™ืŸ ื‘ืจืฉื™ืžืช ื”ื’ื™ื‘ื•ื™ื™ื ื”ืžืœืื™ื

/usr/local/bin/backup-list.sh

ื‘ื“ื™ืงืช ื”ืชืื•ืฉืฉื•ืช

ื”ืชืื•ืฉืฉื•ืช ืžืœืื” ืขื ื’ืœื’ื•ืœ ื›ืœ ื”-WAL ื”ื–ืžื™ืŸ.

ืขืฆื•ืจ ืืช Postgresql.

ืžื—ืง ื”ื›ืœ ืžื”ืชื™ืงื™ื™ื” /var/lib/pgsql/9.6/data.

ื”ืคืขืœ ืืช ื”ืกืงืจื™ืคื˜ /usr/local/bin/backup-fetch.sh ื›ืžืฉืชืžืฉ postgres.

su - postgres
/usr/local/bin/backup-fetch.sh

ื—ื™ืœื•ืฅ ื”ื’ื™ื‘ื•ื™ ื”ื•ืฉืœื.

ื”ื•ืกืฃ recovery.conf ืœืชื™ืงื™ื™ืช /var/lib/pgsql/9.6/data ืขื ื”ืชื•ื›ืŸ ื”ื‘ื.

restore_command = '/usr/local/bin/wal-fetch.sh "%f" "%p"'

ืื ื—ื ื• ืžืชื—ื™ืœื™ื ืืช PostgreSQL. PostgreSQL ื™ืชื—ื™ืœ ืืช ืชื”ืœื™ืš ื”ืฉื—ื–ื•ืจ ืžื”-WALs ื”ืืจื›ื™ื•ืŸ, ื•ืจืง ืื– ื‘ืกื™ืก ื”ื ืชื•ื ื™ื ื™ื™ืคืชื—.

systemctl start postgresql-9.6
tail -fn100 /var/lib/pgsql/9.6/data/pg_log/postgresql-Wed.log

ื”ืชืื•ืฉืฉื•ืช ืœื–ืžืŸ ืžืกื•ื™ื.

ืื ื ืจืฆื” ืœืฉื—ื–ืจ ืืช ื‘ืกื™ืก ื”ื ืชื•ื ื™ื ืขื“ ื“ืงื” ืžืกื•ื™ืžืช, ืื– ื ื•ืกื™ืฃ ืืช ื”ืคืจืžื˜ืจ recovery_target_time ืœ- recovery.conf - ืื ื• ืžืฆื™ื™ื ื™ื ื‘ืื™ื–ื• ืฉืขื” ืœืฉื—ื–ืจ ืืช ื‘ืกื™ืก ื”ื ืชื•ื ื™ื.

restore_command = '/usr/local/bin/wal-fetch.sh "%f" "%p"'
recovery_target_time = '2020-01-29 09:46:25'

ืœืื—ืจ ื”ืฉื—ื–ื•ืจ, ืขื™ื™ืŸ ื‘ื˜ื‘ืœื” indexing_table

 2020-01-29 09:41:25.226198+00
 2020-01-29 09:42:25.336989+00
 2020-01-29 09:43:25.356069+00
 2020-01-29 09:44:25.37381+00
 2020-01-29 09:45:25.392944+00

ืื ื—ื ื• ืžืชื—ื™ืœื™ื ืืช PostgreSQL. PostgreSQL ื™ืชื—ื™ืœ ืืช ืชื”ืœื™ืš ื”ืฉื—ื–ื•ืจ ืžื”-WALs ื”ืืจื›ื™ื•ืŸ, ื•ืจืง ืื– ื‘ืกื™ืก ื”ื ืชื•ื ื™ื ื™ื™ืคืชื—.

systemctl start postgresql-9.6
tail -fn100 /var/lib/pgsql/9.6/data/pg_log/postgresql-Wed.log

ื‘ื“ื™ืงื”

ื™ืฆื™ืจืช ืžืกื“ ื ืชื•ื ื™ื ืฉืœ 1GB ื›ืžืชื•ืืจ ื›ืืŸ https://gist.github.com/ololobus/5b25c432f208d7eb31051a5f238dffff

ื‘ืงืฉืช ื’ื•ื“ืœ ื”ื“ืœื™ ืœืื—ืจ ื”ืคืงืช 1GB ืฉืœ ื ืชื•ื ื™ื.

postgres=# SELECT pg_size_pretty(pg_database_size('test1'));
pg_size_pretty
----------------
1003 MB

s4cmd ื”ื•ื ื›ืœื™ ืฉื•ืจืช ืคืงื•ื“ื” ื—ื™ื ืžื™ ืœืขื‘ื•ื“ื” ืขื ื ืชื•ื ื™ื ื”ืฉื•ื›ื ื™ื ื‘ืื—ืกื•ืŸ Amazon S3. ื›ืœื™ ื”ืฉื™ืจื•ืช ื›ืชื•ื‘ ื‘ืฉืคืช ื”ืชื›ื ื•ืช python, ื•ื‘ืฉืœ ื›ืš ื ื™ืชืŸ ืœื”ืฉืชืžืฉ ื‘ื• ื’ื ื‘ืžืขืจื›ื•ืช ื”ื”ืคืขืœื” Windows ื•ื’ื ื‘-Linux.

ืžืชืงื™ืŸ s4cmd

pip install s4cmd

LZ4

s4cmd --endpoint-url=http://ip-ะฐะดั€ะตั-ัะตั€ะฒะตั€ะฐ-minio:9000 --access-key=xxxx --secret-key=yyyy du -r s3://pg-backups
840540822       s3://pg-backups/wal_005/
840 ะœะ‘ ะฒ ั„ะพั€ะผะฐั‚ะต lz4 ั‚ะพะปัŒะบะพ WAL ะปะพะณะพะฒ

ะŸะพะปะฝั‹ะน ะฑะตะบะฐะฟ ั lz4 - 1GB ะดะฐะฝะฝั‹ั…
time backup_push.sh
real 0m18.582s

ะ ะฐะทะผะตั€ S3 ะฑะฐะบะตั‚ะฐ ะฟะพัะปะต ะฟะพะปะฝะพะณะพ ะฑะตะบะฐะฟะฐ

581480085       s3://pg-backups/basebackups_005/
842374424   s3://pg-backups/wal_005
581 ะœะ‘ ะทะฐะฝะธะผะฐะตั‚ ะฟะพะปะฝั‹ะน ะฑะตะบะฐะฟ

LZMA

ะŸะพัะปะต ะณะตะฝะตั€ะฐั†ะธะธ 1ะ“ะ‘ ะดะฐะฝะฝั‹ั…
338413694       s3://pg-backups/wal_005/
338 ะผะฑ ะปะพะณะพะฒ ะฒ ั„ะพั€ะผะฐั‚ะต lzma

ะ’ั€ะตะผั ะณะตะฝะตั€ะฐั†ะธะธ ะฟะพะปะฝะพะณะพ ะฑะตะบะฐะฟะฐ
time backup_push.sh
real    5m25.054s

ะ ะฐะทะผะตั€ ะฑะฐะบะตั‚ะฐ ะฒ S3
270310495       s3://pg-backups/basebackups_005/
433485092   s3://pg-backups/wal_005/

270 ะผะฑ ะทะฐะฝะธะผะฐะตั‚ ะฟะพะปะฝั‹ะน ะฑะตะบะฐะฟ ะฒ ั„ะพั€ะผะฐั‚ะต lzma

ื‘ืจื•ื˜ืœื™

ะŸะพัะปะต ะณะตะฝะตั€ะฐั†ะธะธ 1ะ“ะ‘ ะดะฐะฝะฝั‹ั…
459229886       s3://pg-backups/wal_005/
459 ะผะฑ ะปะพะณะพะฒ ะฒ ั„ะพั€ะผะฐั‚ะต brotli

ะ’ั€ะตะผั ะณะตะฝะตั€ะฐั†ะธะธ ะฟะพะปะฝะพะณะพ ะฑะตะบะฐะฟะฐ
real    0m23.408s

ะ ะฐะทะผะตั€ ะฑะฐะบะตั‚ะฐ ะฒ S3
312960942       s3://pg-backups/basebackups_005/
459309262   s3://pg-backups/wal_005/

312 ะผะฑ ะทะฐะฝะธะผะฐะตั‚ ะฟะพะปะฝั‹ะน ะฑะตะบะฐะฟ ะฒ ั„ะพั€ะผะฐั‚ะต brotli

ื”ืฉื•ื•ืื” ื‘ื™ืŸ ืชื•ืฆืื•ืช ื‘ืชืจืฉื™ื.

ื”ื™ื›ืจื•ืช ืขื ืžืขืจื›ืช ื”ื’ื™ื‘ื•ื™ wal-g PostgreSQL

ื›ืคื™ ืฉื ื™ืชืŸ ืœืจืื•ืช, Brotli ื“ื•ืžื” ื‘ื’ื•ื“ืœื• ืœ-LZMA, ืืš ื”ื’ื™ื‘ื•ื™ ืžืชื‘ืฆืข ื‘ื–ืžืŸ LZ4.

ืฆ'ืื˜ ืฉืœ ืงื”ื™ืœืช PostgreSQL ื“ื•ื‘ืจืช ื”ืจื•ืกื™ืช: https://t.me/pgsql

ืื ื ืชืŸ ื›ื•ื›ื‘ ืœ-Github ืื ืืชื” ืžืฉืชืžืฉ ื•ื•ืœ-ื’

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”