From c07a5946f8cec144bdc1940ba0a56191281b6594 Mon Sep 17 00:00:00 2001 From: Igor Simdyanov Date: Thu, 6 Mar 2025 21:08:50 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=92=D1=82=D0=BE=D1=80=D0=BE=D0=B5=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BD=D1=8F=D1=82=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 1 + Gemfile.lock | 14 +++++++ app/admin/book.rb | 4 ++ app/models/application_record.rb | 1 + config/application.rb | 6 +++ config/database.yml | 15 ++++++-- config/environments/development.rb | 2 +- config/environments/production.rb | 3 +- db/master/init.sql | 1 + db/master/pg_hba.conf | 15 ++++++++ db/slave/.pgpass | 2 + db/slave/init-slave.sh | 5 +++ docker-compose.yml | 60 +++++++++++++++++++++++++----- 13 files changed, 114 insertions(+), 15 deletions(-) create mode 100644 db/master/init.sql create mode 100644 db/master/pg_hba.conf create mode 100644 db/slave/.pgpass create mode 100755 db/slave/init-slave.sh diff --git a/Gemfile b/Gemfile index fc76bca..0d92e26 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ gem 'puma', '>= 6.5.0' # Базы данных gem 'pg' +gem 'redis-actionpack' # hiredes # Многопоточное выполнение gem 'parallel' diff --git a/Gemfile.lock b/Gemfile.lock index d66b198..8a7c1da 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -316,6 +316,19 @@ GEM rdoc (6.7.0) psych (>= 4.0.0) redcarpet (3.6.0) + redis (5.4.0) + redis-client (>= 0.22.0) + redis-actionpack (5.5.0) + actionpack (>= 5) + redis-rack (>= 2.1.0, < 4) + redis-store (>= 1.1.0, < 2) + redis-client (0.23.2) + connection_pool + redis-rack (3.0.0) + rack-session (>= 0.2.0) + redis-store (>= 1.2, < 2) + redis-store (1.11.0) + redis (>= 4, < 6) regexp_parser (2.9.2) reline (0.5.9) io-console (~> 0.5) @@ -466,6 +479,7 @@ DEPENDENCIES pry-rails puma (>= 6.5.0) rails (>= 8.0.1) + redis-actionpack rspec-rails (>= 7.1) rubocop-performance rubocop-rails diff --git a/app/admin/book.rb b/app/admin/book.rb index a780c59..541e369 100644 --- a/app/admin/book.rb +++ b/app/admin/book.rb @@ -19,19 +19,23 @@ as: :select, label: I18n.t('active_admin.filters.genre'), collection: proc { + #ActiveRecord::Base.connected_to(role: :reading, prevent_writes: true) do # TODO query + декоратор Genre.order(:name) .pluck(:name, :id) .map { |g| [ truncate(g.first, length: 25), g.last ] } + #end } filter :keywords_id_eq, as: :select, label: I18n.t('active_admin.filters.keyword'), collection: proc { + #ActiveRecord::Base.connected_to(role: :reading, prevent_writes: true) do # TODO query + декоратор Keyword.order(:name) .pluck(:name, :id) .map { |k| [ truncate(k.first, length: 25), k.last ] } + #end } controller do diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 08029c7..3f94811 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,4 +1,5 @@ class ApplicationRecord < ActiveRecord::Base primary_abstract_class self.implicit_order_column = 'created_at' + # connects_to database: { writing: :primary, reading: :primary_replica } end diff --git a/config/application.rb b/config/application.rb index 483852d..347e678 100644 --- a/config/application.rb +++ b/config/application.rb @@ -32,6 +32,12 @@ class Application < Rails::Application # Common ones are `templates`, `generators`, or `middleware`, for example. config.autoload_lib(ignore: %w[assets tasks]) # config.eager_load_paths << Rails.root.join('extras') + config.cache_store = :redis_cache_store, { url: ENV['REDIS_CACHE_URL'] } + # config.session_store :redis_store, + # servers: [ENV['REDIS_SESSION_URL']], + # expire_after: 90.minutes, + # key: '_library_session', + # threadsafe: false config.generators do |g| g.org :active_record diff --git a/config/database.yml b/config/database.yml index 48f30ee..a054252 100644 --- a/config/database.yml +++ b/config/database.yml @@ -17,9 +17,18 @@ development: test: <<: *default + <<: *postgre database: library_test production: - <<: *default - <<: *postgre - database: library_production + primary: + <<: *default + <<: *postgre + host: <%= ENV.fetch('POSTGRES_HOST_MASTER', 'localhost') %> + database: library_production + primary_replica: + <<: *default + <<: *postgre + host: <%= ENV.fetch('POSTGRES_HOST_SLAVE', 'localhost') %> + database: library_production + replica: true diff --git a/config/environments/development.rb b/config/environments/development.rb index 7d707e7..645699d 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -26,7 +26,7 @@ end # Change to :null_store to avoid any caching. - config.cache_store = :memory_store + # config.cache_store = :memory_store # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log diff --git a/config/environments/production.rb b/config/environments/production.rb index c5ea502..acdf848 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -35,7 +35,8 @@ config.logger = ActiveSupport::TaggedLogging.logger(STDOUT) # Change to "debug" to log everything (including potentially personally-identifiable information!) - config.log_level = ENV.fetch('RAILS_LOG_LEVEL') { 'info' } + config.log_level = ENV.fetch('RAILS_LOG_LEVEL') { 'debug' } + config.active_record.verbose_query_logs = true # Prevent health checks from clogging up the logs. config.silence_healthcheck_path = '/up' diff --git a/db/master/init.sql b/db/master/init.sql new file mode 100644 index 0000000..9098cdd --- /dev/null +++ b/db/master/init.sql @@ -0,0 +1 @@ +CREATE USER repluser REPLICATION PASSWORD 'repluser'; diff --git a/db/master/pg_hba.conf b/db/master/pg_hba.conf new file mode 100644 index 0000000..e8b923d --- /dev/null +++ b/db/master/pg_hba.conf @@ -0,0 +1,15 @@ +# TYPE DATABASE USER ADDRESS METHOD + +# "local" is for Unix domain socket connections only +local all all trust +host all all 127.0.0.1/32 trust +host all all ::1/128 trust +# Allow replication connections from localhost, by a user with the +# replication privilege. +local replication all trust +host replication all 127.0.0.1/32 trust +host replication all ::1/128 trust + +host replication all 172.18.0.0/16 md5 + +host all all all scram-sha-256 diff --git a/db/slave/.pgpass b/db/slave/.pgpass new file mode 100644 index 0000000..f6d89c1 --- /dev/null +++ b/db/slave/.pgpass @@ -0,0 +1,2 @@ +*:*:*:postgres:postgres +*:*:*:repluser:repluser diff --git a/db/slave/init-slave.sh b/db/slave/init-slave.sh new file mode 100755 index 0000000..db24747 --- /dev/null +++ b/db/slave/init-slave.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e + +rm -rf /var/lib/postgresql/data/* +pg_basebackup --host=master --username=repluser --pgdata=/var/lib/postgresql/data --wal-method=stream --write-recovery-conf diff --git a/docker-compose.yml b/docker-compose.yml index 9c195af..657a9fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,39 @@ services: - db: + # db: + # image: postgres:17 + # environment: + # POSTGRES_USER: 'postgres' + # POSTGRES_PASSWORD: 'postgres' + # volumes: + # - db:/var/lib/postgresql/data + postgresql_master: image: postgres:17 - environment: - POSTGRES_USER: 'postgres' - POSTGRES_PASSWORD: 'postgres' + container_name: master + restart: always + networks: + - db-repl volumes: - - db:/var/lib/postgresql/data + - ./db/data/master:/var/lib/postgresql/data + - ./db/master/pg_hba.conf:/var/lib/postgresql/pg_hba.conf + - ./db/master/init.sql:/docker-entrypoint-initdb.d/init.sql + env_file: + - ./.env.postgresql + + postgresql_slave: + image: postgres:17 + container_name: slave + restart: always + networks: + - db-repl + volumes: + - ./db/slave/.pgpass:/var/lib/postgresql/.pgpass + - ./db/slave/.pgpass:/root/.pgpass + - ./db/data/slave/:/var/lib/postgresql/data + - ./db/master/pg_hba.conf:/var/lib/postgresql/pg_hba.conf + - ./db/slave/init-slave.sh:/var/lib/postgresql/init-slave.sh + env_file: + - ./.env.postgresql + web: tty: true stdin_open: true @@ -22,16 +50,28 @@ services: - .:/rails - "$DOCKER_COMPOSE_ARCHIVE_FOLDER:/rails/db/data" networks: - - default + - db-repl ports: - "8080:3000" depends_on: - - db + - postgresql_master environment: RAILS_LOG_TO_STDOUT: 'yes' PAGER: 'more' - POSTGRES_HOST: 'db' + POSTGRES_HOST_MASTER: 'postgresql_master' + POSTGRES_HOST_SLAVE: 'postgresql_slave' POSTGRES_USER: 'postgres' POSTGRES_PASSWORD: 'postgres' -volumes: - db: + +networks: + db-repl: + driver: bridge + name: db-repl + ipam: + driver: default + config: + - subnet: 172.18.0.0/16 + gateway: 172.18.0.1 + +# volumes: +# db: From a31f96dafa84eeec8a765427e59c01f4ed86e656 Mon Sep 17 00:00:00 2001 From: Igor Simdyanov Date: Thu, 6 Mar 2025 21:09:47 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=92=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=20=D1=81=D0=B5=D1=81=D1=81=D0=B8=D0=B8=20=D0=B2=20redis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/application.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/application.rb b/config/application.rb index 347e678..1ee58af 100644 --- a/config/application.rb +++ b/config/application.rb @@ -33,11 +33,11 @@ class Application < Rails::Application config.autoload_lib(ignore: %w[assets tasks]) # config.eager_load_paths << Rails.root.join('extras') config.cache_store = :redis_cache_store, { url: ENV['REDIS_CACHE_URL'] } - # config.session_store :redis_store, - # servers: [ENV['REDIS_SESSION_URL']], - # expire_after: 90.minutes, - # key: '_library_session', - # threadsafe: false + config.session_store :redis_store, + servers: [ENV['REDIS_SESSION_URL']], + expire_after: 90.minutes, + key: '_library_session', + threadsafe: false config.generators do |g| g.org :active_record