Масштабирование базы данных через шардирование и...

Post on 25-Jul-2015

144 Views

Category:

Technology

10 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Масштабирование базы данныхчерез шардирование ипартиционированиеИванов Денис

2gis.ru

2GIS WebAPI

Данные

•  8 стран

•  250 городов

•  50 тыс населенных пунктов

•  5 млн организаций

•  50 млн гео-объектов

И еще много всего

3

Нагрузка

•  25 млн. пользователей в месяц

•  2000 RPS

•  3 датацентра

4

Много данных

Долгие запросы

Масштабирование БД как решениепроблемы

•  Шардинг

•  Вертикальный

•  Горизонтальный

•  Репликация

7

Партицирование(вертикальный шардинг)

Горизонтальный шардинг

Репликация

1. Партицирование

CREATE TABLE news (

id bigint not null,

category_id int not null,

author character varying not null,

rate int not null,

title character varying

)

01.

02.

03.

04.

05.

06.

07.

15

CREATE TABLE news_1 (

) INHERITS (news)

01.

02.

16

Наследованная таблица•  Будет:

•  Все колонки от родителя

•  "Свои" колонки

•  Не будет:

•  Ограничений (Constraint)

•  Индексов (Index)

•  Триггеров (Trigger)

17

CREATE TABLE news_1 (

CHECK ( category_id = 1 )

) INHERITS (news)

01.

02.

03.

18

Строгое значение

CHECK ( author = 'Denis' )

Список значений

CHECK ( author IN ('Denis', 'Anton', 'Oleg') )

Диапазон значений

CHECK ( rate > 100 AND rate <= 200 )

19

CREATE TABLE news_rate_100_200 (

CHECK ( rate BETWEEN 100 AND 200 )

) INHERITS (news)

CREATE TABLE news_rate_200_300 (

CHECK ( rate BETWEEN 200 AND 300 )

) INHERITS (news)

01.

02.

03.

04.

05.

06.

07.

20

CREATE TABLE news_rate_100_200 (

CHECK ( rate > 100 AND rate <= 200 )

) INHERITS (news)

CREATE TABLE news_rate_201_300 (

CHECK ( rate > 200 AND rate <= 300 )

) INHERITS (news)

01.

02.

03.

04.

05.

06.

07.

21

CREATE TABLE news_1 (

CHECK ( category_id = 1 )

) INHERITS (news)

CREATE TABLE news_rate_100 (

CHECK ( rate = 100 )

) INHERITS (news)

01.

02.

03.

04.

05.

06.

07.

22

CREATE TABLE news_1 (

CHECK ( category_id = 1 )

) INHERITS ( news )

01.

02.

03.

23

CREATE RULE news_insert_to_ 1 AS ON INSERT TO news

WHERE ( category_id = 1 )

DO INSTEAD INSERT INTO news_1 VALUES (NEW.*)

01.

02.

03.

24

CREATE TABLE news_1 (

CHECK ( category_id = 1 )

) INHERITS ( news )

CREATE TABLE news_2 (

CHECK ( category_id = 2 )

) INHERITS ( news )

01.

02.

03.

04.

05.

06.

07.

25

CREATE RULE news_insert_to_ 1 AS ON INSERT TO news

WHERE ( category_id = 1 )

DO INSTEAD INSERT INTO news_1 VALUES (NEW.*)

CREATE RULE news_insert_to_ 2 AS ON INSERT TO news

WHERE ( category_id = 2 )

DO INSTEAD INSERT INTO news_2 VALUES (NEW.*)

01.

02.

03.

04.

05.

06.

07.

26

INSERT INTO news

(id, category_id , title, author, rate)

VALUES

(1, 1 , 'Моя новость #1', 'Ivan', 1)

INSERT INTO news

(id, category_id , title, author, rate)

VALUES

(2, 2 , 'Моя новость #2', 'Oleg', 1)

01.

02.

03.

04.

01.

02.

03.

04.

27

INSERT INTO news

(id, category_id , title, author, rate)

VALUES

(3, 3 , 'Моя новость #3', 'Petr', 1)

01.

02.

03.

04.

28

SELECT * FROM news

id category_id title author rate

1 1 Моя новость #1 Ivan 1

2 2 Моя новость #2 Oleg 1

3 3 Моя новость #3 Petr 1

29

SELECT * FROM news WHERE category_id = 1

id category_id title author rate

1 1 Моя новость #1 Ivan 1

SELECT * FROM news WHERE category_id IN (2, 3)

id category_id title author rate

2 2 Моя новость #2 Oleg 1

3 3 Моя новость #3 Petr 1

30

SELECT * FROM news_1

id category_id title author rate

1 1 Моя новость #1 Ivan 1

SELECT * FROM news_2

id category_id title author rate

2 2 Моя новость #2 Oleg 1

31

SELECT * FROM news_3

ERROR: relation "news_3" does not exist

SELECT * FROM ONLY news

id category_id title author rate

3 3 Моя новость #3 Petr 1

32

INSERT INTO news_1

(id, category_id , title, author, rate)

VALUES

(4, 1 , 'Моя новость #4', 'Ivan', 1)

01.

02.

03.

04.

33

INSERT INTO news_1

(id, category_id , title, author, rate)

VALUES

(4, 4 , 'Моя новость #4', 'Ivan', 1)

ERROR: new row for relation " news_1 " violates

check constraint " news_1_category_id_check "

01.

02.

03.

04.

01.

02.

34

INSERT INTO news

(id, category_id , title, author, rate)

VALUES

(5, 1 , 'Моя новость #5', 'Ivan', 1),

(6, 2 , 'Моя новость #6', 'Oleg', 1),

(7, 3 , 'Моя новость #7', 'Petr', 1)

01.

02.

03.

04.

05.

06.

35

SELECT * FROM news WHERE category_id = 1 LIMIT 1

id category_id title author rate

1 1 Моя новость #1 Ivan 1

SELECT * FROM news_1 LIMIT 1

id category_id title author rate

1 1 Моя новость #1 Ivan 1

36

EXPLAIN ANALYZE

SELECT * FROM news WHERE category_id = 1

...

-> Seq Scan on news ...

Filter: (category_id = 1)

-> Seq Scan on news_1 ...

Filter: (category_id = 1)

...

01.

02.

01.

02.

03.

04.

05.

06.

37

EXPLAIN ANALYZE

SELECT * FROM news_1

...

Seq Scan on news_1

...

01.

02.

01.

02.

03.

38

Точно также:•  UPDATE

•  DELETE

39

CREATE INDEX news_rate_idx ON news (rate)

CREATE INDEX news_1_rate_idx ON news_1 (rate)

CREATE INDEX news_2_rate_idx ON news_2 (rate)

40

PartitionMagic

CREATE TABLE news (

id bigint not null,

category_id int not null,

author character varying not null,

rate int not null,

title character varying

)

01.

02.

03.

04.

05.

06.

07.

42

_2gis_partition_magic(' news ', ' category_id ')

43

INSERT INTO news

(id, category_id , title, author, rate)

VALUES

(1, 1 , 'Моя новость #1', 'Ivan', 1),

(2, 2 , 'Моя новость #2', 'Oleg', 1),

(3, 3 , 'Моя новость #3', 'Petr', 1),

(4, 1 , 'Моя новость #4', 'Ivan', 1),

(5, 1 , 'Моя новость #5', 'Ivan', 1),

(6, 2 , 'Моя новость #6', 'Oleg', 1),

(7, 3 , 'Моя новость #7', 'Petr', 1)

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

44

SELECT * FROM news WHERE category_id = 1

id category_id title author rate

1 1 Моя новость #1 Ivan 1

5 1 Моя новость #5 Ivan 1

SELECT * FROM news_1

id category_id title author rate

1 1 Моя новость #1 Ivan 1

5 1 Моя новость #5 Ivan 1

45

Преимущества:

•  Создание недостающих партиций при вставке

•  Актуальная структура таблиц:

•  Колонки

•  Индексы

•  Проверки

•  Триггеры

46

https://github.com/2gis/partition_magic

2. Горизонтальный шардинг

CREATE TABLE news (

id bigint not null,

category_id int not null

CONSTRAINT category_id_check CHECK (category_id = 1 ),

author character varying not null,

rate int not null,

title character varying

);

01.

02.

03.

04.

05.

06.

07.

08.

50

CREATE INDEX news_category_id_idx ON news

USING btree( category_id );

01.

02.

51

CREATE EXTENSION postgres_fdw;

CREATE SERVER news_1_server

FOREIGN DATA WRAPPER postgres_fdw

OPTIONS (host ' 127.0.0.1 ', port ' 5432 ', dbname ' news_1 ');

CREATE USER MAPPING FOR postgres

SERVER news_1_server

OPTIONS (user ' postgres ', password ' postgres ');

01.

02.

03.

04.

05.

06.

07.

08.

09.

52

CREATE FOREIGN TABLE news_1 (

id bigint not null,

category_id int not null,

author character varying not null,

rate int not null,

title character varying

)

SERVER news_1_server

OPTIONS (schema_name ' public ', table_name ' news ')

01.

02.

03.

04.

05.

06.

07.

08.

09.

53

CREATE VIEW news AS

SELECT * FROM news_1

UNION ALL

SELECT * FROM news_2

01.

02.

03.

04.

54

CREATE RULE news_insert AS ON INSERT TO news

DO INSTEAD NOTHING;

CREATE RULE news_update AS ON UPDATE TO news

DO INSTEAD NOTHING;

CREATE RULE news_delete AS ON DELETE TO news

DO INSTEAD NOTHING;

01.

02.

03.

04.

05.

06.

07.

08.

55

CREATE RULE news_insert_to_1 AS ON INSERT TO news

WHERE ( category_id = 1 )

DO INSTEAD INSERT INTO news_1 VALUES (NEW.*);

CREATE RULE news_insert_to_2 AS ON INSERT TO news

WHERE ( category_id = 2 )

DO INSTEAD INSERT INTO news_2 VALUES (NEW.*);

01.

02.

03.

04.

05.

06.

07.

56

INSERT INTO news

(id, category_id , title, author, rate)

VALUES

(1, 1 , 'Моя новость #1', 'Ivan', 1),

(2, 2 , 'Моя новость #2', 'Oleg', 1),

(3, 3 , 'Моя новость #3', 'Petr', 1),

(4, 1 , 'Моя новость #4', 'Ivan', 1),

(5, 1 , 'Моя новость #5', 'Ivan', 1),

(6, 2 , 'Моя новость #6', 'Oleg', 1),

(7, 3 , 'Моя новость #7', 'Petr', 1)

01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

57

SELECT * FROM news

id category_id title author rate

1 1 Моя новость #1 Ivan 1

4 1 Моя новость #4 Ivan 1

5 1 Моя новость #5 Ivan 1

2 2 Моя новость #2 Oleg 1

6 2 Моя новость #6 Oleg 1

58

SELECT * FROM news WHERE category_id = 2

id category_id title author rate

2 2 Моя новость #2 Oleg 1

6 2 Моя новость #6 Oleg 1

SELECT * FROM news_2

id category_id title author rate

2 2 Моя новость #2 Oleg 1

6 2 Моя новость #6 Oleg 1

59

EXPLAIN ANALYZE

SELECT * FROM news

...

-> Foreign Scan on news_1

-> Foreign Scan on news_2

...

01.

02.

01.

02.

03.

04.

60

Подведём итоги•  Партицирование

•  Просто

•  Один сервер

•  Прирост производительности в 3-4 раза

•  Горизонтальный шардинг

•  Немного сложнее партицирования

•  Разные сервера для разных шардов

61

Вопросы?

Иванов Денис

dv.ivanov@2gis.ru

62

top related