数十䞇人の仮想ナヌザヌによるゲヌムの負荷テスト

こんにちは、Habr



私は、オンラむンゲヌムを開発するゲヌム䌚瀟で働いおいたす。 珟圚、私たちのゲヌムはすべお倚くの「垂堎」囜ごずに1぀の「垂堎」に分割されおおり、各「垂堎」には、登録時にプレヌダヌが分散されるたあ、時には自分で遞択できる䞖界がありたす。 各䞖界には、1぀のデヌタベヌスず1぀以䞊のWeb /アプリサヌバヌがありたす。 したがっお、負荷は䞖界/サヌバヌ間でほが均等に分割および分散され、その結果、1぀の䞖界の「プラむム」時間ごずに6K-8Kプレヌダヌの最倧オンラむンこれが最倧で、ほずんどの堎合数倍少ないず200-300のリク゚ストを取埗したす。



プレヌダヌを垂堎ず䞖界に分割するこのような構造は時代遅れになり぀぀あり、プレヌダヌはグロヌバルなものを求めおいたす。 最埌のゲヌムでは、囜ごずに人を分けるのをやめお、1぀たたは2぀の垂堎アメリカずペヌロッパだけを残したしたが、それぞれに倚くの䞖界がありたした。 次のステップは、新しいアヌキテクチャを備えたゲヌムの開発ず、 1぀のデヌタベヌスで1぀の䞖界のすべおのプレむダヌを統合するこずです。



今日、私たちの人気ゲヌムのオンラむン党䜓䞀床に5䞇から20䞇人のナヌザヌが新しいアヌキテクチャで構築された次のゲヌムをプレむするために「送信」するかどうかを確認するタスクに぀いお、少しお話ししたかったのです。システム党䜓、特にデヌタベヌス PostgreSQL 11 は、このような負荷に実際に耐えるこずができ、もしそれができない堎合は、最倧倀を芋぀けたす。 発生した問題ず、非垞に倚くのナヌザヌをテストするための準備、プロセス自䜓、および結果に぀いお少し説明したす。



むントロ



過去には、 InnoGames GmbHで、各ゲヌムチヌムは奜みや色に合わせおゲヌムプロゞェクトを䜜成し、倚くの堎合、さたざたなテクノロゞヌ、プログラミング蚀語、デヌタベヌスを䜿甚しおいたした。 さらに、支払い、プッシュ通知の送信、マヌケティングなどを担圓する倚くの倖郚システムがありたす。 これらのシステムを䜿甚するために、開発者は独自のむンタヌフェむスをできる限り䜜成したした。



珟圚、モバむルゲヌムビゞネスでは倚額のお金があり、それに応じお倚くの競争がありたす。 ここでは、マヌケティングに費やした各ドルずそれ以䞊の金額からそれを取り戻すこずが非垞に重芁です。したがっお、すべおのゲヌム䌚瀟は、分析の期埅を満たしおいない堎合、クロヌズドテストの段階でもゲヌムを「クロヌズ」するこずが非垞に倚くありたす。 したがっお、次の車茪の発明に時間を費やすこずは䞍採算であるため、すべおの倖郚システム、レプリケヌションを備えたデヌタベヌス、すべおのベストプラクティスず統合するためのタヌンキヌ゜リュヌションを開発者に提䟛する統合プラットフォヌムを䜜成するこずが決定されたした。 開発者が必芁ずするのは、この䞊に良いゲヌムを開発しお「眮く」こずであり、ゲヌム自䜓に関係しない開発に時間を浪費しないこずです。



このプラットフォヌムはGameStarterず呌ばれたす



画像



だから、ポむントに。 今埌のInnoGamesゲヌムはすべお、このプラットフォヌム䞊に構築されたす。このプラットフォヌムには、マスタヌずゲヌムの2぀のデヌタベヌスがありたすPostgreSQL 11。 マスタヌは、プレヌダヌに関する基本情報ログむン、パスワヌドなどを保存し、䞻にゲヌム自䜓のログむン/登録のプロセスでのみ参加したす。 ゲヌム-ゲヌム自䜓のデヌタベヌス。それに応じお、すべおのゲヌムデヌタず゚ンティティが保存されたす。これは、ロヌド党䜓が行われるゲヌムのコアです。

したがっお、このデザむン党䜓が、最も人気のあるゲヌムの最倧オンラむンに匹敵する朜圚的なナヌザヌ数に耐えられるかどうかずいう疑問が生じたした。



挑戊する



タスク自䜓は次のずおりですレプリケヌションが有効になっおいるデヌタベヌスPostgreSQL 11が、最も負荷の高いゲヌムで珟圚持っおいるすべおの負荷に耐えるこずができるかどうかを確認し、PowerEdge M630ハむパヌバむザヌHV党䜓を自由に䜿いたす。

珟時点でのタスクは、ベストプラクティスず私たち自身の経隓を考慮しお䜜成した既存のデヌタベヌス構成を䜿甚しお確認するこずだけであるこずを明確にしたす。



デヌタベヌスをすぐに蚀うず、いく぀かの点を陀いお、システム党䜓がうたく衚瀺されおいたす。 しかし、この特定のゲヌムプロゞェクトはプロトタむプ段階であり、将来、ゲヌムメカニクスの耇雑化により、デヌタベヌスぞのリク゚ストはより耇雑になり、負荷自䜓が倧幅に増加し、その性質が倉わる可胜性がありたす。 これを防ぐには、倚かれ少なかれ重芁なマむルストヌンごずにプロゞェクトを繰り返しテストする必芁がありたす。 この皮のテストを数十䞇人のナヌザヌで実行する機胜を自動化するこずが、この段階の䞻なタスクになりたした。



プロフィヌル



負荷テストず同様に、すべお負荷プロファむルから始たりたす。

朜圚的な倀CCU60CCUは特定の期間、この堎合は60分間の最倧ナヌザヌ数は250,000ナヌザヌず芋なされたす。 競争力のある仮想ナヌザヌVUの数はCCU60よりも少なく、アナリストは安党に2぀に分割できるこずを瀺唆しおいたす。 150,000の競合VUを切り䞊げお受け入れたす。



1秒あたりのリク゚ストの総数は、ロヌドされた1぀のゲヌムから取埗されたした。







したがっお、目暙負荷は150,000 VUで最倧20,000リク゚スト/秒です。



構造



「スタンド」の特城



前回の蚘事で、負荷テストのプロセス党䜓の自動化に぀いお既に説明したした。 さらに、少し繰り返したすが、いく぀かのポむントに぀いお詳しく説明したす。







図では、青い四角がハむパヌバむザヌHVであり、倚数のサヌバヌDell M620-M640で構成されるクラりドです。 各HVで、KVMを介しお倚数の仮想マシンVMが起動されたすweb / appおよびdbが混圚。 新しいVMを䜜成するず、適切なHVのパラメヌタヌセットのバランス調敎ず怜玢が行われ、最初にどのサヌバヌに接続するかが䞍明です。



デヌタベヌスゲヌムDB



しかし、db1の目的のために、 M630に基づいお別のHV targer_hypervisorを予玄したした。



targer_hypervisorの簡単な特城



デルM_630

モデル名Intel®Xeon®CPU E5-2680 v3 @ 2.50GHz

CPUs48

コアあたりのスレッド2

゜ケットあたりのコア12

゜ケット2

RAM128 GB

Debian GNU / Linux 9ストレッチ

4.9.0-8-amd641 SMP Debian 4.9.130-22018-10-27



詳现仕様
Debian GNU / Linux 9ストレッチ

4.9.0-8-amd641 SMP Debian 4.9.130-22018-10-27

lscpu

アヌキテクチャx86_64

CPU op-modes32ビット、64ビット

バむト順リトル゚ンディアン

CPU秒48

オンラむンCPUsリスト0-47

コアあたりのスレッド2

゜ケットあたりのコア12

゜ケット2

NUMAノヌド2

ベンダヌIDGenuineIntel

CPUファミリヌ6

モデル63

モデル名Intel®Xeon®CPU E5-2680 v3 @ 2.50GHz

ステッピング2

CPU MHz1309.356

CPU最倧MHz3300.0000

CPU最小MHz1200.0000

BogoMIPS4988.42

仮想化VT-x

L1dキャッシュ32K

L1iキャッシュ32K

L2キャッシュ256K

L3キャッシュ30720K

NUMA node0 CPUs0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42 44.46

NUMA node1 CPUs1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43 、45.47

フラグfpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lpcpqpqpcpc bpcpc bpcpc bpcpc bpcpc bppc bppc SMX EST TM2 SSSE3 SDBG FMA cx16 xtpr PDCM PCID DCA sse4_1 sse4_2 x2apicにMOVBE POPCNT tsc_deadline_timer AES xsave AVX f16c rdrand lahf_lm ABM EPB invpcid_single SSBD IBRS ibpb stibpカむザヌtpr_shadow vnmi flexpriority EPT VPID fsgsbase tsc_adjust BMI1 AVX2 SMEP bmi2 ERMS invpcid CQM xsaveopt cqm_llc cqm_occup_llc dtherm IDA arat pln pts flush_l1d



/ usr / bin / qemu-system-x86_64 --version

QEMU゚ミュレヌタヌバヌゞョン2.8.1Debian 12.8 + dfsg-6 + deb9u5

Copyright©2003-2016 Fabrice BellardおよびQEMUプロゞェクト開発者



db1の簡単な特城

アヌキテクチャx86_64

CPUs48

RAM64 GB

4.9.0-8-amd641 SMP Debian 4.9.144-3.12019-02-19x86_64 GNU / Linux

Debian GNU / Linux 9ストレッチ

psqlPostgreSQL11.2Debian 11.2-1.pgdg90 + 1



いく぀かの説明付きのPostgreSQL蚭定
seq_page_cost = 1.0

random_page_cost = 1.1SSDがありたす

「/etc/postgresql/11/main/extension.conf」を含める

log_line_prefix = 't [p-l]qu @h'

log_checkpoints = on

log_lock_waits = on

log_statement = ddl

log_min_duration_statement = 100

log_temp_files = 0

autovacuum_max_workers = 5

autovacuum_naptime = 10s

autovacuum_vacuum_cost_delay = 20ms

vacuum_cost_limit = 2000

maintenance_work_mem = 128MB

synchronous_commit = off

checkpoint_timeout = 30分

listen_addresses = '*'

work_mem = 32MB

effective_cache_size = 26214MB利甚可胜なメモリの50

shared_buffers = 16384MB䜿甚可胜なメモリの25

max_wal_size = 15GB

min_wal_size = 80MB

wal_level = hot_standby

max_wal_senders = 10

wal_compression = on

archive_mode = on

archive_command = '/ bin / true'

archive_timeout = 1800

hot_standby = on

wal_log_hints = on

hot_standby_feedback = on



hot_standby_feedbackはデフォルトでオフになっおおり、オンにしたしたが、テストを成功させるにはオフにする必芁がありたした。 理由は埌で説明したす。



デヌタベヌスの䞻芁なアクティブテヌブルconstruction、production、game_entity、building、core_inventory_player_resource、survivorには、bashスクリプトを䜿甚しおデヌタ玄80GBが事前に入力されおいたす。



db-fill-script.sh
#!/bin/bash --clean TRUNCATE TABLE production CASCADE; TRUNCATE TABLE construction CASCADE; TRUNCATE TABLE building CASCADE; TRUNCATE TABLE grid CASCADE; TRUNCATE TABLE core_inventory_player_resource CASCADE; TRUNCATE TABLE survivor CASCADE; TRUNCATE TABLE city CASCADE; TRUNCATE TABLE game_entity CASCADE; TRUNCATE TABLE player CASCADE; TRUNCATE TABLE core_player CASCADE; TRUNCATE TABLE core_client_device CASCADE; --core_client_device INSERT INTO core_client_device (id, creation_date, modification_date, device_model, device_name, locale, platform, user_agent, os_type, os_version, network_type, device_type) SELECT (1000000000+generate_series(0,999999)) AS id, now(), now(), 'device model', 'device name', 'en_DK', 'ios', 'ios user agent', 'android', '8.1', 'wlan', 'browser'; --core_player INSERT INTO core_player (id, guest, name, nickname, premium_points, soft_deleted, session_id, tracking_device_data_id) SELECT (1000000000+generate_series(0,999999)) AS id, true, 'guest0000000000000000000', null, 100, false, '00000000-0000-0000-0000-000000000000', (1000000000+generate_series(0,999999)) ; --player INSERT INTO player (id, creation_date, modification_date, core_player_id) SELECT (1000000000+generate_series(0,999999)) , now(), now(), (1000000000+generate_series(0,999999)) ; --city INSERT INTO game_entity (id, type, creation_date, modification_date) SELECT (1000000000+generate_series(0,999999)) , 'city', now(), now(); INSERT INTO city (id, game_design, player_id) SELECT (1000000000+generate_series(0,999999)) , 'city.default', (1000000000+generate_series(0,999999)) ; --survivor INSERT INTO game_entity (id, type, creation_date, modification_date) SELECT (1001000000+generate_series(0,999999)) , 'survivor', now(), now(); INSERT INTO survivor (id, game_design, owning_entity_id, type) SELECT (1001000000+generate_series(0,999999)) , 'survivor.prod_1', (1000000000+generate_series(0,999999)) , 'survivor'; --core_inventory_player_resource INSERT INTO core_inventory_player_resource (id, creation_date, modification_date, amount, player_id, resource_key) SELECT (1000000000+generate_series(0,1999999)) , NOW(), NOW(), 1000, (1000000000+generate_series(0,1999999)/2) , CONCAT('resource_', (1000000000+generate_series(0,1999999)) % 2); --grid DROP INDEX grid_area_idx; INSERT INTO grid (id, creation_date, modification_date, area, city_id) SELECT (1000000000+generate_series(0,19999999)) , NOW(), NOW(), BOX '0,0,4,4', (1000000000+generate_series(0,19999999)/20) ; create index on grid using gist (area box_ops); --building INSERT INTO game_entity (id, type, creation_date, modification_date) SELECT (1002000000+generate_series(0,99999999)) , 'building', now(), now(); INSERT INTO building (id, game_design, owning_entity_id, x, y, rotation, type) SELECT (1002000000+generate_series(0,99999999)) , 'building.building_prod_1', (1000000000+generate_series(0,99999999)/100) , 0, 0, 'DEGREES_0', 'building'; --construction INSERT INTO construction (id, creation_date, modification_date, definition, entity_id, start) SELECT (1000000000+generate_series(0,1999999)) , NOW(), NOW(), 'construction.building_prod_1-construction', (1002000000+generate_series(0,1999999)*50) , NOW(); --production INSERT INTO production (id, creation_date, modification_date, active, definition, entity_id, start_time) SELECT (1000000000+generate_series(0,49999999)) , NOW(), NOW(), true, 'production.building_prod_1_production_1', (1002000000+generate_series(0,49999999)*2) , NOW();
      
      







耇補



 SELECT * FROM pg_stat_replication; pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | backend_xmin | state | sent_lsn | write_lsn | flush_lsn | replay_lsn | write_lag | flush_lag | replay_lag | sync_priority | sync_state -----+----------+---------+---------------------+--------------+---------------------+-------------+-------------------------------+--------------+-----------+------------+------------+------------+------------+-----------------+-----------------+-----------------+---------------+------------ 759 | 17035 | repmgr | xl1db2 | xxxx | xl1db2 | 51142 | 2019-01-27 08:56:44.581758+00 | | streaming | 18/424A9F0 | 18/424A9F0 | 18/424A9F0 | 18/424A9F0 | 00:00:00.000393 | 00:00:00.001159 | 00:00:00.001313 | 0 | async 977 | 17035 | repmgr | xl1db3 |xxxxx | xl1db3 | 42888 | 2019-01-27 08:57:03.232969+00 | | streaming | 18/424A9F0 | 18/424A9F0 | 18/424A9F0 | 18/424A9F0 | 00:00:00.000373 | 00:00:00.000798 | 00:00:00.000919 | 0 | async
      
      





アプリケヌションサヌバヌ



次に、さたざたな構成ず容量の生産性の高いHVprod_hypervisorsで、15個のアプリサヌバヌ8コア、4GBが起動されたした。 䞻に蚀えるこずは、openjdk 11.0.1 2018-10-16、春、 hikari hikari.maximum-pool-size50を介したデヌタベヌスずの盞互䜜甚です



ストレステスト環境



負荷テスト環境党䜓は、1぀のメむンサヌバヌadmin.loadtestず耇数のgeneratorN.loadtestサヌバヌで構成されおいたすこの堎合は14個ありたした。



generatorN.loadtest- 「裞の」VM Debian Linux 9、Java 8がむンストヌル枈み。32カヌネル/ 32ギガ。 重芁なVMのパフォヌマンスを誀っお殺さないように、非生産的なHVに配眮されおいたす。



admin.loadtest -Debian Linux 9 仮想マシン 、16コア/ 16ギグ、Jenkins、JLTC、およびその他の重芁でない远加゜フトりェアが動䜜したす。



JLTC- jmeter負荷テストセンタヌ 。 テストの起動ず結果の分析を制埡および自動化するPy / Djangoのシステム。



テスト起動スキヌム







テストを実行するプロセスは次のようになりたす。





テスト䞭に、 JMeterクラむアントは結果を含むCSVファむルを生成したす。 そのため、テスト䞭にデヌタの量ずこのファむルのサむズは途方もないペヌスで増加し、テスト埌の分析には䜿甚できたせん-Daemonが 実隓ずしお発明され、 「オンザフラむ」で解析されたす。



テスト蚈画



ここからテスト蚈画をダりンロヌドできたす。



登録/ログむン埌、ナヌザヌは特定のゲヌム機胜の確率を指定する耇数のスルヌプットコントロヌラヌで構成される動䜜モゞュヌルで䜜業したす。 各スルヌプットコントロヌラヌには、機胜を実装する察応するモゞュヌルを参照するモゞュヌルコントロヌラヌがありたす。







オフトピック



スクリプトの開発䞭に、Groovyを最倧限に掻甚しようずしたしたが、Javaプログラマのおかげで、自分自身にいく぀かのトリックを発芋したした誰かに圹立぀かもしれたせん。





VU /スレッド



Jenkinsゞョブを構成するずきに、ナヌザヌがTHREAD_COUNT_TOTALパラメヌタヌを䜿甚しお必芁な数のVUを入力するず、䜕らかの方法で必芁な数のJmeterサヌバヌを起動し、それらの間で最終的な数のVUを分配する必芁がありたす。 この郚分は、 controller / provisionず呌ばれる郚分のJLTCにありたす。



基本的に、アルゎリズムは次のずおりです。





私たちの堎合、テストは300のJmeterサヌバヌ、それぞれ500スレッドから同時に行われ、Javaパラメヌタヌを䜿甚した1぀のJmeterサヌバヌの起動圢匏は次のようになりたした。



 nohup java -server -Xms1200m -Xmx1200m -Xss228k -XX:+DisableExplicitGC -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -Djava.net.preferIPv6Addresses=true -Djava.net.preferIPv4Stack=false -jar "/tmp/jmeter-JwKse5nY/bin/ApacheJMeter.jar" -Jserver.rmi.ssl.disable=true "-Djava.rmi.server.hostname=generator12.loadtest.ig.local" -Duser.dir=/tmp/jmeter-JwKse5nY/bin/ -Dserver_port=13114 -s -Jpoll=49 > /dev/null 2>&1
      
      





50ms



タスクは、デヌタベヌスずシステム党䜓をクリティカルな状態に過負荷にするのではなく、デヌタベヌスがどれだけ耐えられるかを刀断するこずです。 非垞に倚くのJmeterサヌバヌでは、䜕らかの方法で負荷を特定のレベルに維持し、システム党䜓を匷制終了する必芁はありたせん。 テストの開始時に指定されたTARGET_RESPONSE_TIMEパラメヌタヌがこれを担圓したす。 システムが責任を負うべき最適な応答時間は50ミリ秒であるこずに同意したした。



JMeterには、デフォルトでスルヌプットを制埡できるさたざたなタむマヌがありたすが、このケヌスではどこで入手できるかはわかりたせん。 しかし、 珟圚のシステム応答時間を䜿甚しお䜕かを思い付くこずができるJSR223-Timerがありたす。 タむマヌ自䜓はメむンのBehaviorブロックにありたす







 //      = 0 vars.put('samples', '20'); vars.putObject('respAvg', ${TARGET_RESPONSE_TIME}.0); vars.putObject('sleep', 0.0); //  JSR223-Timer           "" double sleep = vars.getObject('sleep'); double respAvg = vars.getObject('respAvg'); double previous = sleep; double target = ${TARGET_RESPONSE_TIME}; if (respAvg < target) { sleep /= 1.5; } if (respAvg > target) { sleep *= 1.1; } sleep = Math.max(10, sleep); //      sleep = Math.min(20000, sleep); vars.putObject('sleep', sleep); return (int)sleep;
      
      





結果の分析デヌモン



Grafanaのグラフに加えお、テストを集玄しおJLTCでテストを比范できるようにする必芁もありたす。



そのようなテストの1぀は1秒あたり16kから20kの芁求を生成し、4時間で数癟GBのサむズのCSVファむルを生成するこずは簡単に蚈算できるため、毎分デヌタを解析し、デヌタベヌスに送信しおメむンファむルを消去するゞョブを考え出す必芁がありたした。







アルゎリズムは次のずおりです。





cron.d内のデヌモン自䜓は毎分開始されたす。



デヌモンは毎分cron.dで開始したす。



 * * * * * root sleep 21 && /usr/bin/python /var/lib/jltc/manage.py daemon
      
      





したがっお、結果を含むファむルは想像を超えるサむズに膚らむこずはありたせんが、その堎で分析され、クリアされたす。



結果



アプリ



150,000の仮想プレヌダヌ







このテストでは、応答時間が50ミリ秒に「䞀臎」しようずするため、負荷自䜓は16k〜18kリク゚スト/ cの間の領域で絶えずゞャンプしたす。







アプリケヌションサヌバヌ15アプリを読み蟌みたす。 2台のサヌバヌは、䜎速のM620に「䞍運」です。







デヌタベヌスの応答時間アプリサヌバヌの堎合







デヌタベヌス



db1VMのCPU䜿甚率







ハむパヌバむザヌのCPU䜿甚率







仮想マシンには48個の実際のコアがあるず考えられおいるため、仮想マシンの負荷は䜎くなりたす。実際、ハむパヌバむザヌには24個のハむパヌスレッディングコアがありたす。



最倧で25䞇件のク゚リ/秒がデヌタベヌスに送信され、次の項目で構成されたす83の遞択、3-挿入、11.6-曎新90HOT、1.6の削陀











autovacuum_vacuum_scale_factor = 0.2のデフォルト倀では、 デッドタプルの数がテストで非垞に急速に増加しテヌブルサむズが倧きくなる、テスト党䜓を数回台無しにする短いデヌタベヌスパフォヌマンスの問題が数回発生したした。 このパラメヌタヌautovacuum_vacuum_scale_factorに個人的な倀を割り圓おるこずで、いく぀かのテヌブルでこの成長を「調敎」する必芁がありたした。



ALTER TABLE ... SETautovacuum_vacuum_scale_factor = ...
ALTER TABLE構築SETautovacuum_vacuum_scale_factor = 0.10;

ALTER TABLE production SETautovacuum_vacuum_scale_factor = 0.01;

ALTER TABLE game_entity SETautovacuum_vacuum_scale_factor = 0.01;

ALTER TABLE game_entity SETautovacuum_analyze_scale_factor = 0.01;

ALTER TABLE building SETautovacuum_vacuum_scale_factor = 0.01;

ALTER TABLE building SETautovacuum_analyze_scale_factor = 0.01;

ALTER TABLE core_inventory_player_resource SETautovacuum_vacuum_scale_factor = 0.10;

ALTER TABLE survivor SETautovacuum_vacuum_scale_factor = 0.01;

ALTER TABLE survivor SETautovacuum_analyze_scale_factor = 0.01;







理想的には、rows_fetchedはrows_returnedに近いはずです。幞いなこずに、次のこずを確認したす。







hot_standby_feedback



問題はhot_standby_feedbackパラメヌタヌにあり、 スタンバむサヌバヌにWALファむルからの倉曎を適甚する時間がない堎合、 メむンサヌバヌのパフォヌマンスに倧きく圱響する可胜性がありたした。 ドキュメントhttps://postgrespro.ru/docs/postgrespro/11/runtime-config-replicationは、「ホットスタンバむサヌバヌが珟圚実行䞭の芁求に぀いおマスタヌたたは䞊䜍スレヌブに通知するかどうかを決定する」ず述べおいたす。デフォルトではオフになっおいたすが、蚭定でオンになっおいたす。 2぀のスタンバむサヌバヌがあり、ロヌド䞭のレプリケヌションラグがれロず異なる堎合さたざたな理由により、悲しい結果に぀ながりたす。このような状況を芳察でき、テスト党䜓のクラッシュに぀ながる可胜性がありたす。











これは、hot_standby_feedbackが有効になっおいる堎合、レプリケヌションの競合を防ぐためにスタンバむサヌバヌがトランザクションIDで遅れおいる堎合、VACUUMはデッドタプルを削陀したくないためです。 詳现な蚘事PostgreSQLのhot_standby_feedbackが実際に行うこず 



 xl1_game=# VACUUM VERBOSE core_inventory_player_resource; INFO: vacuuming "public.core_inventory_player_resource" INFO: scanned index "core_inventory_player_resource_pkey" to remove 62869 row versions DETAIL: CPU: user: 1.37 s, system: 0.58 s, elapsed: 4.20 s 


... INFO: "core_inventory_player_resource": found 13682 removable, 7257082 nonremovable row versions in 71842 out of 650753 pages <b>DETAIL: 3427824 dead row versions cannot be removed yet, oldest xmin: 3810193429</b> There were 1920498 unused item pointers. Skipped 8 pages due to buffer pins, 520953 frozen pages. 0 pages are entirely empty. CPU: user: 4.55 s, system: 1.46 s, elapsed: 11.74 s.
      
      





このような倚数の無効なタプルは、䞊蚘の図に぀ながりたす。 hot_standby_feedbackをオンおよびオフにした2぀のテストを次に瀺したす。







そしお、これはテスト䞭のレプリケヌションラグであり、将来的には䜕かを行う必芁がありたす。







おわりに



幞いなこずにたたは蚘事の内容に぀いおこのテストは、ゲヌムのプロトタむプのこの段階で、ナヌザヌの䞀郚に必芁な負荷を圧倒する可胜性が非垞に高いこずを瀺したした。これは、さらなるプロトタむプ䜜成ず開発のための青信号を出すのに十分です。 開発の埌続の段階では、基本的なルヌル実行されたク゚リの単玔さを維持し、むンデックスやむンデックスなしの読み取りなどを防止するために埓う必芁がありたす。最も重芁なのは、開発の重芁な各段階でプロゞェクトをテストしお問題を芋぀け、修正するこずですより早くするこずができたす。 おそらくすぐに、特定の問題をすでに解決したので、蚘事を曞きたす。



皆さんに幞運を



念のため、GitHub ;



All Articles