{"id":375591,"date":"2024-05-21T06:28:16","date_gmt":"2024-05-21T06:28:16","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=375591"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=375591","title":{"rendered":"<span>CDC \u043d\u0430 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u0430\u0445<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0421\u0443\u0442\u044c CDC \u0432\u00a0\u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u043e\u043d \u00ab\u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u00bb \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0430 \u0432\u0438\u0434\u0430 CDC:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0436\u0443\u0440\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e \u0437\u0430\u0445\u0432\u0430\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0442\u043e \u0435\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0438\u043d\u0443\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u041d\u0435 \u0441\u0430\u043c\u044b\u0439 \u043b\u0443\u0447\u0448\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e CDC \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u043a\u0440\u043e\u043d\u0443 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0411\u0414 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f; \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0411\u0414.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u043b\u044c\u0437\u044f \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u0438\/\u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e, \u0435\u0441\u043b\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u043d\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u0430\u0442 \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043b\u044e\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u0411\u044b\u0441\u0442\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0441 \u0437\u0430\u0445\u0432\u0430\u0442\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 \u0436\u0443\u0440\u043d\u0430\u043b \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u0443 \u043d\u0430\u0441 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u0430 \u043f\u043e \u043c\u0438\u043d\u0443\u0441\u0430\u043c:<\/p>\n<ul>\n<li>\n<p>\u0421\u043b\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0431\u041e\u043b\u044c\u0448\u0430\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0438\u0434\u0430 CDC<\/p>\n<\/li>\n<li>\n<p>\u0421\u043b\u043e\u0436\u043d\u0435\u0435 \u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043d\u0438\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u0432 \u0442\u043e\u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043b\u044e\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0412\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043d\u0430\u0448\u0435\u0439 \u0411\u0414: \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439<\/p>\n<\/li>\n<li>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0411\u0414, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u044b \u0447\u0438\u0442\u0430\u0435\u043c WAL-\u0436\u0443\u0440\u043d\u0430\u043b<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c real-time \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c event-driven \u043f\u043e\u0434\u0445\u043e\u0434<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0438\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043d\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c CDC \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <a href=\"https:\/\/debezium.io\/\" rel=\"noopener noreferrer nofollow\">Debezium<\/a>. \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0438\u043c <a href=\"https:\/\/github.com\/k0rsakov\/debezium_cdc_example\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c<\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0441\u0442\u044c \u0432\u0441\u0451 \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u0442\u0430\u0442\u044c\u0435. \u0410 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a.<\/p>\n<hr\/>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>docker-compose.yaml<\/code> \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0432\u0441\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443.<\/p>\n<details class=\"spoiler\">\n<summary>docker-compose.yaml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">version: '2'  services:    zookeeper:     image: quay.io\/debezium\/zookeeper:2.5     ports:       - \"2181:2181\"       - \"2888:2888\"       - \"3888:3888\"    kafka:     image: quay.io\/debezium\/kafka:2.5     ports:       - \"9092:9092\"     links:       - zookeeper     environment:       - ZOOKEEPER_CONNECT=zookeeper:2181    postgres:     image: quay.io\/debezium\/example-postgres:2.5     ports:       - \"5432:5432\"     environment:       - POSTGRES_USER=postgres       - POSTGRES_PASSWORD=postgres    connect:     image: quay.io\/debezium\/connect:2.5     ports:       - \"8083:8083\"     links:       - kafka       - postgres     environment:       - BOOTSTRAP_SERVERS=kafka:9092       - GROUP_ID=1       - CONFIG_STORAGE_TOPIC=my_connect_configs       - OFFSET_STORAGE_TOPIC=my_connect_offsets       - STATUS_STORAGE_TOPIC=my_connect_statuses    control-center:     image: confluentinc\/cp-enterprise-control-center:7.6.1     hostname: control-center     ports:       - \"9021:9021\"     depends_on:       - kafka     environment:       CONTROL_CENTER_BOOTSTRAP_SERVERS: \"kafka:9092\"       CONTROL_CENTER_REPLICATION_FACTOR: \"1\"   debezium-ui:     image: quay.io\/debezium\/debezium-ui:2.5     platform: linux\/x86_64     depends_on:       - kafka       - connect       - zookeeper     ports:       - \"8081:8080\"     environment:       - KAFKA_CONNECT_URIS=http:\/\/connect:8083    ch_server:     image: clickhouse\/clickhouse-server:24.4.1     ports:       - \"8123:8123\"     environment:       CLICKHOUSE_USER: click       CLICKHOUSE_PASSWORD: click <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0436\u043d\u043e.<\/strong> \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u044b \u0432 <code>docker-compose.yaml<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u044b \u043e\u0442\u00a0\u0441\u0430\u043c\u043e\u0433\u043e debezium. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0447\u0430\u0441\u0442\u044c \u0448\u0430\u0433\u043e\u0432 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0437\u0430 \u0432\u0430\u0441. \u041d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0451 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c <a href=\"https:\/\/debezium.io\/documentation\/reference\/2.5\/index.html\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439<\/a>.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c config <code>register-postgres.json<\/code><\/p>\n<details class=\"spoiler\">\n<summary>register-postgres.json<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{   \"name\": \"inventory-connector\",   \"config\": {     \"connector.class\": \"io.debezium.connector.postgresql.PostgresConnector\",     \"tasks.max\": \"1\",     \"database.hostname\": \"postgres\",     \"database.port\": \"5432\",     \"database.user\": \"postgres\",     \"database.password\": \"postgres\",     \"database.dbname\": \"postgres\",     \"topic.prefix\": \"dbserver1\",     \"schema.include.list\": \"inventory\"   } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code class=\"bash\">curl -i -X POST -H \"Accept:application\/json\" -H  \"Content-Type:application\/json\" http:\/\/localhost:8083\/connectors\/ -d @register-postgres.json<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"http:\/\/localhost:9021\/\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:9021\/<\/a> \u0438 \u0437\u0430\u0439\u0442\u0438 \u0432 <code>Topics<\/code>, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0442\u043e\u043f\u0438\u043a\u0438 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u043d\u0430\u0448\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438\u0437 \u0411\u0414.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/943\/3ed\/dec\/9433eddec0e886262471c0967f7d1b5a.png\" alt=\"\u0422\u043e\u043f\u0438\u043a\u0438 \u0432 Kafka\" title=\"\u0422\u043e\u043f\u0438\u043a\u0438 \u0432 Kafka\" width=\"3110\" height=\"1424\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/943\/3ed\/dec\/9433eddec0e886262471c0967f7d1b5a.png\"\/><\/p>\n<div><figcaption>\u0422\u043e\u043f\u0438\u043a\u0438 \u0432 Kafka<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 CDC. \u0412\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u0411\u0414 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0432 Kafka.<\/p>\n<hr\/>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043b\u044f\u00a0\u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0438 \u0441\u044d\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u043c \u00ab\u0440\u0430\u0431\u043e\u0447\u0443\u044e\u00bb \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443.<\/p>\n<p>\u0414\u043b\u044f\u00a0\u044d\u0442\u043e\u0433\u043e \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0442\u0430\u0440\u044b\u0435.<\/p>\n<p>\u041d\u043e\u00a0\u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a\u00a0\u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435; \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code class=\"bash\">python3.11 -m venv venv &amp;&amp; \\ source venv\/bin\/activate &amp;&amp; \\ pip install --upgrade pip &amp;&amp; \\ pip install -r requirements.txt<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>table_simulation.py<\/code> \u0438 \u0432 \u043d\u0435\u0433\u043e \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<details class=\"spoiler\">\n<summary>table_simulation.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import uuid import json import time import random import requests  import pandas as pd from connectors_to_databases import PostgreSQL  pg = PostgreSQL(     host='localhost',     port=5432,     login='postgres',     password='postgres', )   def insert_user():     r = requests.get(url='https:\/\/randomuser.me\/api\/')      d = json.loads(r.text)     dict_user = d['results'][0]      d_ = {         'first_name': [dict_user['name']['first']],         'last_name': [dict_user['name']['last']],         'email': [dict_user['email']],     }      df = pd.DataFrame(d_)      try:         pg.insert_df(             df=df,             pg_table_schema='inventory',             pg_table_name='customers',         )     except Exception as ex:         pass      time.sleep(2)   def update_user():     df_id = pg.execute_to_df(         '''         SELECT id FROM inventory.customers         '''     )      len_list = len(df_id.id)      random_user = random.randint(0, len_list)      try:         pg.execute_script(             f'''             UPDATE                 inventory.customers             SET                 first_name = '{str(uuid.uuid4())}',                 last_name = '{str(uuid.uuid4())}'             WHERE                 id = {df_id.id[random_user]}             '''         )     except Exception as ex:         pass      time.sleep(2)   while True:     if random.randint(1, 1000) % 2 == 0:         print('INSERT new USER')         insert_user()     else:         print('UPDATE current USER')         update_user() <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u0430\u0448\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435<\/p>\n<pre><code class=\"bash\">source venv\/bin\/activate<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u043c \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"bash\">python table_simulation.py<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"http:\/\/localhost:9021\/\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:9021\/<\/a> \u0438 \u0437\u0430\u0439\u0442\u0438 \u0432 \u0442\u043e\u043f\u0438\u043a <code>dbserver1.inventory.customers<\/code><\/p>\n<p>\u0422\u0430\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u0432 Kafka \u0438 \u044d\u0442\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u0432\u0441\u0435 \u043d\u0430\u0448\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u0437 WAL-\u0436\u0443\u0440\u043d\u0430\u043b\u0430.<\/p>\n<p>\u041d\u0438\u0436\u0435 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043a \u043d\u0430\u043c \u0432 Kafka<\/p>\n<details class=\"spoiler\">\n<summary>Message<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{   \"schema\": {     \"type\": \"struct\",     \"fields\": [       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"int32\",             \"optional\": false,             \"default\": 0,             \"field\": \"id\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"first_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"last_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"email\"           }         ],         \"optional\": true,         \"name\": \"dbserver1.inventory.customers.Value\",         \"field\": \"before\"       },       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"int32\",             \"optional\": false,             \"default\": 0,             \"field\": \"id\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"first_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"last_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"email\"           }         ],         \"optional\": true,         \"name\": \"dbserver1.inventory.customers.Value\",         \"field\": \"after\"       },       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"version\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"connector\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"name\"           },           {             \"type\": \"int64\",             \"optional\": false,             \"field\": \"ts_ms\"           },           {             \"type\": \"string\",             \"optional\": true,             \"name\": \"io.debezium.data.Enum\",             \"version\": 1,             \"parameters\": {               \"allowed\": \"true,last,false,incremental\"             },             \"default\": \"false\",             \"field\": \"snapshot\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"db\"           },           {             \"type\": \"string\",             \"optional\": true,             \"field\": \"sequence\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"schema\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"table\"           },           {             \"type\": \"int64\",             \"optional\": true,             \"field\": \"txId\"           },           {             \"type\": \"int64\",             \"optional\": true,             \"field\": \"lsn\"           },           {             \"type\": \"int64\",             \"optional\": true,             \"field\": \"xmin\"           }         ],         \"optional\": false,         \"name\": \"io.debezium.connector.postgresql.Source\",         \"field\": \"source\"       },       {         \"type\": \"string\",         \"optional\": false,         \"field\": \"op\"       },       {         \"type\": \"int64\",         \"optional\": true,         \"field\": \"ts_ms\"       },       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"id\"           },           {             \"type\": \"int64\",             \"optional\": false,             \"field\": \"total_order\"           },           {             \"type\": \"int64\",             \"optional\": false,             \"field\": \"data_collection_order\"           }         ],         \"optional\": true,         \"name\": \"event.block\",         \"version\": 1,         \"field\": \"transaction\"       }     ],     \"optional\": false,     \"name\": \"dbserver1.inventory.customers.Envelope\",     \"version\": 1   },   \"payload\": {     \"before\": {       \"id\": 1003,       \"first_name\": \"Edward\",       \"last_name\": \"Walker\",       \"email\": \"ed@walker.com\"     },     \"after\": {       \"id\": 1003,       \"first_name\": \"2df7fb35-4c33-4742-9e56-10073c54937e\",       \"last_name\": \"07f6a1e6-6a0a-4d51-98c3-9e67ea49b3b5\",       \"email\": \"ed@walker.com\"     },     \"source\": {       \"version\": \"2.5.4.Final\",       \"connector\": \"postgresql\",       \"name\": \"dbserver1\",       \"ts_ms\": 1715153932452,       \"snapshot\": \"false\",       \"db\": \"postgres\",       \"sequence\": \"[\\\"34498256\\\",\\\"34498256\\\"]\",       \"schema\": \"inventory\",       \"table\": \"customers\",       \"txId\": 779,       \"lsn\": 34498256,       \"xmin\": null     },     \"op\": \"u\",     \"ts_ms\": 1715153932842,     \"transaction\": null   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u0430\u0436\u043d\u0430\u044f \u0437\u0434\u0435\u0441\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u00a0\u2014 \u044d\u0442\u043e \u0432\u043e\u0442 \u044d\u0442\u043e\u0442 \u043a\u0443\u0441\u043e\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"json\">... \"payload\": {     \"before\": {       \"id\": 1003,       \"first_name\": \"Edward\",       \"last_name\": \"Walker\",       \"email\": \"ed@walker.com\"     },     \"after\": {       \"id\": 1003,       \"first_name\": \"2df7fb35-4c33-4742-9e56-10073c54937e\",       \"last_name\": \"07f6a1e6-6a0a-4d51-98c3-9e67ea49b3b5\",       \"email\": \"ed@walker.com\"     },     \"source\": {       \"version\": \"2.5.4.Final\",       \"connector\": \"postgresql\",       \"name\": \"dbserver1\",       \"ts_ms\": 1715153932452,       \"snapshot\": \"false\",       \"db\": \"postgres\",       \"sequence\": \"[\\\"34498256\\\",\\\"34498256\\\"]\",       \"schema\": \"inventory\",       \"table\": \"customers\",       \"txId\": 779,       \"lsn\": 34498256,       \"xmin\": null     }, ...<\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430\u043c \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0447\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u0411\u0414 <strong>\u0434\u043e<\/strong> \u0438 \u0447\u0442\u043e \u0441\u0442\u0430\u043b\u043e <strong>\u043f\u043e\u0441\u043b\u0435<\/strong> \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0424\u043e\u0440\u043c\u0430\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9C%D0%B5%D0%B4%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE_%D0%BC%D0%B5%D0%BD%D1%8F%D1%8E%D1%89%D0%B5%D0%B5%D1%81%D1%8F_%D0%B8%D0%B7%D0%BC%D0%B5%D1%80%D0%B5%D0%BD%D0%B8%D0%B5\" rel=\"noopener noreferrer nofollow\">SCD2<\/a> \u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e \u043a\u043b\u044e\u0447\u0443.<\/p>\n<p>\u0412\u0441\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u043e\u0442\u043e\u043a\u0430 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438: Spark, Flink, etc<\/p>\n<p>\u041d\u043e \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u043a\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0442\u043e\u043f\u0438\u043a\u0438 Kafka \u0447\u0435\u0440\u0435\u0437 ClickHouse.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u044f \u0440\u0430\u043d\u0435\u0435 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b ClickHouse \u0432 \u043d\u0430\u0448 <code>docker-compose.yaml<\/code>.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a ClickHouse \u0447\u0435\u0440\u0435\u0437 \u043b\u044e\u0431\u043e\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0438\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 cli, \u044f \u0431\u0443\u0434\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 DBeaver.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0433\u043b\u0443\u0431\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u0435\u043c\u0443 kafka-engine \u0432 ClickHouse, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 <a href=\"https:\/\/clickhouse.com\/docs\/en\/engines\/table-engines\/integrations\/kafka\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439<\/a>.<\/p>\n<hr\/>\n<p>\u041d\u0438\u0436\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u043e\u043f\u0438\u043a <code>dbserver1.inventory.customers<\/code> \u043a ClickHouse<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c consumer \u0434\u043b\u044f Kafka:<\/p>\n<pre><code class=\"sql\">DROP TABLE IF EXISTS customers_kafka;  CREATE TABLE customers_kafka (   payload String,   \"schema\" String )   ENGINE = Kafka    SETTINGS     kafka_broker_list = 'kafka',     kafka_topic_list = 'dbserver1.inventory.customers',     kafka_group_name = 'foo',     kafka_format = 'JSON';<\/code><\/pre>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0442\u043e\u043f\u0438\u043a\u0430:<\/p>\n<pre><code class=\"sql\">DROP TABLE IF EXISTS customers_kafka_mv;           CREATE TABLE customers_kafka_mv (   payload String,   \"schema\" String )   ENGINE = MergeTree()   ORDER BY (payload);<\/code><\/pre>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u0430\u0442.\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0443\u0436\u0435 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0442\u043e\u043f\u0438\u043a\u0430 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443:<\/p>\n<pre><code class=\"sql\">DROP TABLE IF EXISTS mv_customers_kafka;  CREATE MATERIALIZED VIEW mv_customers_kafka TO customers_kafka_mv AS SELECT * FROM customers_kafkasql<\/code><\/pre>\n<p>\u0418 \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"sql\">SELECT count(*) FROM customers_kafka_mv<\/code><\/pre>\n<p>\u0422\u043e \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u043e\u0435\u00a0\u0431\u044b\u043b\u043e \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432\u00a0\u0434\u0430\u043d\u043d\u044b\u0439 \u0442\u043e\u043f\u0438\u043a Kafka. \u0418 \u0442\u0430\u043a\u0436\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u0438\u0437\u00a0\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. <\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a\u00a0\u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432\u00a0\u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON, \u0442\u043e \u0434\u043b\u044f \u00ab\u0440\u0430\u0437\u0431\u043e\u0440\u0430\u00bb \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 JSON \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c\u0438 <a href=\"https:\/\/clickhouse.com\/docs\/en\/sql-reference\/functions\/json-functions\" rel=\"noopener noreferrer nofollow\">\u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438<\/a> \u0432\u00a0ClickHouse.<\/p>\n<hr\/>\n<p>\u041d\u0430\u00a0\u044d\u0442\u043e\u043c \u0432\u0441\u0451. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u00a0\u0441\u0442\u0430\u0442\u044c\u0435\u00a0\u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437\u00a0\u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u00a0\u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c. \u041f\u0440\u0438\u00a0\u0432\u044b\u0431\u043e\u0440\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439 \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u043d\u0430\u00a0\u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u0438 \u0431\u0438\u0437\u043d\u0435\u0441\u0430, \u0433\u0434\u0435 \u0435\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u0435\u0442\u0435\u043d\u0446\u0438\u0438 \u0438 \u043f\u0440. \u0412\u00a0\u0446\u0435\u043b\u043e\u043c, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438 \u043d\u0435\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c ClickHouse \u0434\u043b\u044f\u00a0\u0447\u0442\u0435\u043d\u0438\u044f \u0442\u043e\u043f\u0438\u043a\u043e\u0432, \u0430\u00a0\u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0430\u00a0Python \u0438\u043b\u0438\u00a0\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u2011\u0431\u0430\u0442\u0447\u0438\u043d\u0433 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c Apache Airflow.<\/p>\n<p>\u0420\u0435\u0437\u044e\u043c\u0435: \u0417\u0430\u0445\u0432\u0430\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438 \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u0443\u044e \u0446\u0435\u043b\u044c \u2013 \u0441\u0432\u043e\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/812797\/\"> https:\/\/habr.com\/ru\/articles\/812797\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0421\u0443\u0442\u044c CDC \u0432\u00a0\u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u043e\u043d \u00ab\u0437\u0430\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u00bb \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0430 \u0432\u0438\u0434\u0430 CDC:<\/p>\n<ul>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0436\u0443\u0440\u043d\u0430\u043b\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e \u0437\u0430\u0445\u0432\u0430\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0442\u043e \u0435\u0441\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0438\u043d\u0443\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u041d\u0435 \u0441\u0430\u043c\u044b\u0439 \u043b\u0443\u0447\u0448\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e CDC \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u043a\u0440\u043e\u043d\u0443 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0411\u0414 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f; \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0411\u0414.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u043b\u044c\u0437\u044f \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0435 \u0438\/\u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e, \u0435\u0441\u043b\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u043d\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u0430\u0442 \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043b\u044e\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u0411\u044b\u0441\u0442\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0441 \u0437\u0430\u0445\u0432\u0430\u0442\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 \u0436\u0443\u0440\u043d\u0430\u043b \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u0443 \u043d\u0430\u0441 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u0430 \u043f\u043e \u043c\u0438\u043d\u0443\u0441\u0430\u043c:<\/p>\n<ul>\n<li>\n<p>\u0421\u043b\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u043e<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0431\u041e\u043b\u044c\u0448\u0430\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u0438\u0434\u0430 CDC<\/p>\n<\/li>\n<li>\n<p>\u0421\u043b\u043e\u0436\u043d\u0435\u0435 \u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043d\u0438\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u0432 \u0442\u043e\u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u043b\u044e\u0441\u044b:<\/p>\n<ul>\n<li>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0412\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043d\u0430\u0448\u0435\u0439 \u0411\u0414: \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439<\/p>\n<\/li>\n<li>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0411\u0414, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u044b \u0447\u0438\u0442\u0430\u0435\u043c WAL-\u0436\u0443\u0440\u043d\u0430\u043b<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c real-time \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c event-driven \u043f\u043e\u0434\u0445\u043e\u0434<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0438\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043d\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c CDC \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <a href=\"https:\/\/debezium.io\/\" rel=\"noopener noreferrer nofollow\">Debezium<\/a>. \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c \u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0438\u043c <a href=\"https:\/\/github.com\/k0rsakov\/debezium_cdc_example\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c<\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0441\u0442\u044c \u0432\u0441\u0451 \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u0442\u0430\u0442\u044c\u0435. \u0410 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a.<\/p>\n<hr\/>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>docker-compose.yaml<\/code> \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0432\u0441\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443.<\/p>\n<details class=\"spoiler\">\n<summary>docker-compose.yaml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">version: '2'  services:    zookeeper:     image: quay.io\/debezium\/zookeeper:2.5     ports:       - \"2181:2181\"       - \"2888:2888\"       - \"3888:3888\"    kafka:     image: quay.io\/debezium\/kafka:2.5     ports:       - \"9092:9092\"     links:       - zookeeper     environment:       - ZOOKEEPER_CONNECT=zookeeper:2181    postgres:     image: quay.io\/debezium\/example-postgres:2.5     ports:       - \"5432:5432\"     environment:       - POSTGRES_USER=postgres       - POSTGRES_PASSWORD=postgres    connect:     image: quay.io\/debezium\/connect:2.5     ports:       - \"8083:8083\"     links:       - kafka       - postgres     environment:       - BOOTSTRAP_SERVERS=kafka:9092       - GROUP_ID=1       - CONFIG_STORAGE_TOPIC=my_connect_configs       - OFFSET_STORAGE_TOPIC=my_connect_offsets       - STATUS_STORAGE_TOPIC=my_connect_statuses    control-center:     image: confluentinc\/cp-enterprise-control-center:7.6.1     hostname: control-center     ports:       - \"9021:9021\"     depends_on:       - kafka     environment:       CONTROL_CENTER_BOOTSTRAP_SERVERS: \"kafka:9092\"       CONTROL_CENTER_REPLICATION_FACTOR: \"1\"   debezium-ui:     image: quay.io\/debezium\/debezium-ui:2.5     platform: linux\/x86_64     depends_on:       - kafka       - connect       - zookeeper     ports:       - \"8081:8080\"     environment:       - KAFKA_CONNECT_URIS=http:\/\/connect:8083    ch_server:     image: clickhouse\/clickhouse-server:24.4.1     ports:       - \"8123:8123\"     environment:       CLICKHOUSE_USER: click       CLICKHOUSE_PASSWORD: click <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0436\u043d\u043e.<\/strong> \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u044b \u0432 <code>docker-compose.yaml<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u044b \u043e\u0442\u00a0\u0441\u0430\u043c\u043e\u0433\u043e debezium. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0447\u0430\u0441\u0442\u044c \u0448\u0430\u0433\u043e\u0432 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u0437\u0430 \u0432\u0430\u0441. \u041d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0451 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c <a href=\"https:\/\/debezium.io\/documentation\/reference\/2.5\/index.html\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439<\/a>.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c config <code>register-postgres.json<\/code><\/p>\n<details class=\"spoiler\">\n<summary>register-postgres.json<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{   \"name\": \"inventory-connector\",   \"config\": {     \"connector.class\": \"io.debezium.connector.postgresql.PostgresConnector\",     \"tasks.max\": \"1\",     \"database.hostname\": \"postgres\",     \"database.port\": \"5432\",     \"database.user\": \"postgres\",     \"database.password\": \"postgres\",     \"database.dbname\": \"postgres\",     \"topic.prefix\": \"dbserver1\",     \"schema.include.list\": \"inventory\"   } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code class=\"bash\">curl -i -X POST -H \"Accept:application\/json\" -H  \"Content-Type:application\/json\" http:\/\/localhost:8083\/connectors\/ -d @register-postgres.json<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"http:\/\/localhost:9021\/\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:9021\/<\/a> \u0438 \u0437\u0430\u0439\u0442\u0438 \u0432 <code>Topics<\/code>, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0442\u043e\u043f\u0438\u043a\u0438 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u043d\u0430\u0448\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446 \u0438\u0437 \u0411\u0414.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0422\u043e\u043f\u0438\u043a\u0438 \u0432 Kafka<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 CDC. \u0412\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u0411\u0414 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0432 Kafka.<\/p>\n<hr\/>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043b\u044f\u00a0\u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u0438 \u0441\u044d\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u043c \u00ab\u0440\u0430\u0431\u043e\u0447\u0443\u044e\u00bb \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443.<\/p>\n<p>\u0414\u043b\u044f\u00a0\u044d\u0442\u043e\u0433\u043e \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0442\u0430\u0440\u044b\u0435.<\/p>\n<p>\u041d\u043e\u00a0\u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a\u00a0\u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435; \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code class=\"bash\">python3.11 -m venv venv &amp;&amp; \\ source venv\/bin\/activate &amp;&amp; \\ pip install --upgrade pip &amp;&amp; \\ pip install -r requirements.txt<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>table_simulation.py<\/code> \u0438 \u0432 \u043d\u0435\u0433\u043e \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:<\/p>\n<details class=\"spoiler\">\n<summary>table_simulation.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import uuid import json import time import random import requests  import pandas as pd from connectors_to_databases import PostgreSQL  pg = PostgreSQL(     host='localhost',     port=5432,     login='postgres',     password='postgres', )   def insert_user():     r = requests.get(url='https:\/\/randomuser.me\/api\/')      d = json.loads(r.text)     dict_user = d['results'][0]      d_ = {         'first_name': [dict_user['name']['first']],         'last_name': [dict_user['name']['last']],         'email': [dict_user['email']],     }      df = pd.DataFrame(d_)      try:         pg.insert_df(             df=df,             pg_table_schema='inventory',             pg_table_name='customers',         )     except Exception as ex:         pass      time.sleep(2)   def update_user():     df_id = pg.execute_to_df(         '''         SELECT id FROM inventory.customers         '''     )      len_list = len(df_id.id)      random_user = random.randint(0, len_list)      try:         pg.execute_script(             f'''             UPDATE                 inventory.customers             SET                 first_name = '{str(uuid.uuid4())}',                 last_name = '{str(uuid.uuid4())}'             WHERE                 id = {df_id.id[random_user]}             '''         )     except Exception as ex:         pass      time.sleep(2)   while True:     if random.randint(1, 1000) % 2 == 0:         print('INSERT new USER')         insert_user()     else:         print('UPDATE current USER')         update_user() <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u0430\u0448\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435<\/p>\n<pre><code class=\"bash\">source venv\/bin\/activate<\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u043c \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"bash\">python table_simulation.py<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"http:\/\/localhost:9021\/\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:9021\/<\/a> \u0438 \u0437\u0430\u0439\u0442\u0438 \u0432 \u0442\u043e\u043f\u0438\u043a <code>dbserver1.inventory.customers<\/code><\/p>\n<p>\u0422\u0430\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u0432 Kafka \u0438 \u044d\u0442\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u0432\u0441\u0435 \u043d\u0430\u0448\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u0437 WAL-\u0436\u0443\u0440\u043d\u0430\u043b\u0430.<\/p>\n<p>\u041d\u0438\u0436\u0435 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043a \u043d\u0430\u043c \u0432 Kafka<\/p>\n<details class=\"spoiler\">\n<summary>Message<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{   \"schema\": {     \"type\": \"struct\",     \"fields\": [       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"int32\",             \"optional\": false,             \"default\": 0,             \"field\": \"id\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"first_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"last_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"email\"           }         ],         \"optional\": true,         \"name\": \"dbserver1.inventory.customers.Value\",         \"field\": \"before\"       },       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"int32\",             \"optional\": false,             \"default\": 0,             \"field\": \"id\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"first_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"last_name\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"email\"           }         ],         \"optional\": true,         \"name\": \"dbserver1.inventory.customers.Value\",         \"field\": \"after\"       },       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"version\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"connector\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"name\"           },           {             \"type\": \"int64\",             \"optional\": false,             \"field\": \"ts_ms\"           },           {             \"type\": \"string\",             \"optional\": true,             \"name\": \"io.debezium.data.Enum\",             \"version\": 1,             \"parameters\": {               \"allowed\": \"true,last,false,incremental\"             },             \"default\": \"false\",             \"field\": \"snapshot\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"db\"           },           {             \"type\": \"string\",             \"optional\": true,             \"field\": \"sequence\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"schema\"           },           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"table\"           },           {             \"type\": \"int64\",             \"optional\": true,             \"field\": \"txId\"           },           {             \"type\": \"int64\",             \"optional\": true,             \"field\": \"lsn\"           },           {             \"type\": \"int64\",             \"optional\": true,             \"field\": \"xmin\"           }         ],         \"optional\": false,         \"name\": \"io.debezium.connector.postgresql.Source\",         \"field\": \"source\"       },       {         \"type\": \"string\",         \"optional\": false,         \"field\": \"op\"       },       {         \"type\": \"int64\",         \"optional\": true,         \"field\": \"ts_ms\"       },       {         \"type\": \"struct\",         \"fields\": [           {             \"type\": \"string\",             \"optional\": false,             \"field\": \"id\"           },     <\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-375591","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/375591","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=375591"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/375591\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=375591"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=375591"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=375591"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}