MySQL挑戰:100k連線 - Percona資料庫效能部落格
在這篇文章中,我想探索一種與MySQL建立100,000個連線的方法。不只是空閒連線,而是執行查詢。
你真的需要MySQL100,000個連線,你可能會問?雖然看起來有點過分,但我在客戶部署中看到了很多不同的設定。有些部署了一個應用程式連線池,每個池中有100個應用程式伺服器和1,000個連線。有些應用程式使用“如果查詢太慢,會重新嘗試連線”的技術,這是一種可怕的做法。它可以導致滾雪球效應,並可以在幾秒鐘內建立數千個與MySQL的連線。
所以現在我想設定一個超出預期的目標,看看我們是否能夠實現它。
構建
我將使用以下硬體:
由packet.net提供的裸機伺服器,例項大小:c2.medium.x86
物理核心@ 2.2 GHz
(1 X AMD EPYC 7401P)
記憶體:64 GB ECC RAM
儲存:INTEL SSDDC S4500,480GB
這是伺服器級SATA SSD。
我將使用其中五個盒子,原因如下。一個用於MySQL伺服器的盒子和四個用於客戶端連線的盒子。
對於伺服器,我將使用帶有執行緒池外掛的Percona Server for MySQL 8.0.13-4。該外掛將需要支援數千個連線。
初始伺服器設定
網路設定(Ansible格式):
- { name: 'net.core.somaxconn', value: 32768 } - { name: 'net.core.rmem_max', value: 134217728 } - { name: 'net.core.wmem_max', value: 134217728 } - { name: 'net.ipv4.tcp_rmem', value: '4096 87380 134217728' } - { name: 'net.ipv4.tcp_wmem', value: '4096 87380 134217728' } - { name: 'net.core.netdev_max_backlog', value: 300000 } - { name: 'net.ipv4.tcp_moderate_rcvbuf', value: 1 } - { name: 'net.ipv4.tcp_no_metrics_save', value: 1 } - { name: 'net.ipv4.tcp_congestion_control', value: 'htcp' } - { name: 'net.ipv4.tcp_mtu_probing', value: 1 } - { name: 'net.ipv4.tcp_timestamps', value: 0 } - { name: 'net.ipv4.tcp_sack', value: 0 } - { name: 'net.ipv4.tcp_syncookies', value: 1 } - { name: 'net.ipv4.tcp_max_syn_backlog', value: 4096 } - { name: 'net.ipv4.tcp_mem', value: '50576 64768 98152' } - { name: 'net.ipv4.ip_local_port_range', value: '4000 65000' } - { name: 'net.ipv4.netdev_max_backlog', value: 2500 } - { name: 'net.ipv4.tcp_tw_reuse', value: 1 } - { name: 'net.ipv4.tcp_fin_timeout', value: 5 } |
這些是推薦用於10Gb網路和高併發工作負載的典型設定。
限制systemd的設定:
[Service] LimitNOFILE=1000000 LimitNPROC=500000 |
以及my.cnf中MySQL的相關設定:
back_log=3500 max_connections=110000 |
對於客戶端,我將使用sysbench版本0.5而不是1.0.x,原因如下所述。
發出工作負載:
sysbench --test=sysbench/tests/db/select.lua --mysql-host=139.178.82.47 --mysql-user=sbtest --mysql-password=sbtest --oltp-tables-count=10 --report-interval=1 --num-threads=10000 --max-time=300 --max-requests=0 --oltp-table-size=10000000 --rand-type=uniform --rand-init=on run |
1. 設定10,000個連線
這個很容易,因為沒有太多的事要做。我們只用一個客戶就可以做到這一點。但是您可能在客戶端遇到以下錯誤:
FATAL: error 2004: Can't create TCP/IP socket (24)
這是由開啟檔案限制引起的,這也是TCP / IP套接字的限制。這可以透過設定:
ulimit -n 100000
我們觀察到效能:
[ 26s] threads: 10000, tps: 0.00, reads: 33367.48, writes: 0.00, response time: 3681.42ms (95%), errors: 0.00, reconnects: 0.00 <p class="indent">[ 27s] threads: 10000, tps: 0.00, reads: 33289.74, writes: 0.00, response time: 3690.25ms (95%), errors: 0.00, reconnects: 0.00 |
2. 設定25,000個連線
當有25,000個連線,我們在MySQL端遇到錯誤:
Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug |
如果您嘗試查詢有關此錯誤的資訊,可能會發現以下文章:https: //www.percona.com/blog/2013/02/04/cant_create_thread_errno_11/
但是在我們的情況下它並沒有幫助,因為我們已將所有限制設定得足夠高:
cat /proc/`pidof mysqld`/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 500000 500000 processes Max open files 1000000 1000000 files Max locked memory 16777216 16777216 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 255051 255051 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us |
在我們開始使用執行緒池功能的地方:https: //www.percona.com/doc/percona-server/8.0/performance/threadpool.html 加上:
thread_handling = pool - of - threads
到my.cnf並重啟Percona Server,結果:
[ 7s] threads: 25000, tps: 0.00, reads: 33332.57, writes: 0.00, response time: 974.56ms (95%), errors: 0.00, reconnects: 0.00 <p class="indent">[ 8s] threads: 25000, tps: 0.00, reads: 33187.01, writes: 0.00, response time: 979.24ms (95%), errors: 0.00, reconnects: 0.00 |
我們有相同的吞吐量,但實際上95%的響應時間已經從3690毫秒改善到979毫秒(由於執行緒池)。
3. 50,000個連線
這是我們遇到的最大挑戰。首先,嘗試在sysbench中獲取50,000個連線,我們遇到以下錯誤:
FATAL: error 2003: Can't connect to MySQL server on '139.178.82.47' (99)
Error (99) 是神秘的,它意味著:無法分配請求的地址。
它來自應用程式可以開啟的埠限制。預設情況下,我的系統是
cat /proc/sys/net/ipv4/ip_local_port_range : 32768 60999 |
這表示只有28,231個可用埠--60999減去32768 - 或者您可以與給定IP地址建立或建立TCP連線的限制。您可以在客戶端和伺服器上使用更廣泛的範圍擴充套件它:
echo 4000 65000 > /proc/sys/net/ipv4/ip_local_port_range |
這將為我們提供61,000個連線,但這非常接近一個IP地址的限制(最大埠為65535)。這裡的關鍵點是,如果我們想要更多的連線,我們需要為MySQL伺服器分配更多的IP地址。為了實現100,000個連線,我將在執行MySQL的伺服器上使用兩個IP地址。
在整理出埠範圍後,我們遇到了sysbench的以下問題:
sysbench 0.5: multi-threaded system evaluation benchmark Running the test with following options: Number of threads: 50000 FATAL: pthread_create() for thread #32352 failed. errno = 12 (Cannot allocate memory) |
在這種情況下,這是sysbench記憶體分配(即lua子系統)的問題。Sysbench只能為32,351個連線分配記憶體。這是一個在sysbench 1.0.x中更嚴重的問題。
Sysbench 1.0.x限制
Sysbench 1.0.x使用不同的Lua JIT,即使有4000個連線也會遇到記憶體問題,所以在sysbench 1.0.x中不可能超過4000連線
因此,與Percona Server相比,我們似乎比sysbench更快地達到了極限。為了使用更多連線,我們需要使用多個sysbench客戶端,如果32,351連線是sysbench的限制,我們必須使用至少四個sysbench客戶端來獲得多達100,000個連線。
對於50,000個連線,我將使用2個伺服器(每個伺服器執行單獨的sysbench),每個伺服器執行來自sysbench的25,000個執行緒。
每個sysbench的結果如下所示:
[ 29s] threads: 25000, tps: 0.00, reads: 16794.09, writes: 0.00, response time: 1799.63ms (95%), errors: 0.00, reconnects: 0.00 <p class="indent">[ 30s] threads: 25000, tps: 0.00, reads: 16491.03, writes: 0.00, response time: 1800.70ms (95%), errors: 0.00, reconnects: 0.00 |
所以我們有相同的吞吐量(總共16794 * 2 = 33588 tps),但95%的響應時間翻了一番。這是預料之中的,因為與25,000個連線基準測試相比,我們使用的連線數是原來的兩倍。
3. 75,000個連線
要實現75,000個連線,我們將使用三個帶sysbench的伺服器,每個伺服器執行25,000個執行緒。
每個sysbench的結果:
[ 157s] threads: 25000, tps: 0.00, reads: 11633.87, writes: 0.00, response time: 2651.76ms (95%), errors: 0.00, reconnects: 0.00 <p class="indent">[ 158s] threads: 25000, tps: 0.00, reads: 10783.09, writes: 0.00, response time: 2601.44ms (95%), errors: 0.00, reconnects: 0.00 |
4. 100,000個連線
實現75k和100k連線沒有任何意義。我們只需啟動一個額外的伺服器並啟動sysbench。對於100,000個連線,我們需要四個伺服器用於sysbench,每個伺服器顯示:
[ 101s] threads: 25000, tps: 0.00, reads: 8033.83, writes: 0.00, response time: 3320.21ms (95%), errors: 0.00, reconnects: 0.00 <p class="indent">[ 102s] threads: 25000, tps: 0.00, reads: 8065.02, writes: 0.00, response time: 3405.77ms (95%), errors: 0.00, reconnects: 0.00 |
因此我們具有相同的吞吐量(總共8065 * 4 = 32260 tps),響應時間為3405毫秒95%。
這是一個非常重要的要點:使用100k連線並使用執行緒池,95%的響應時間甚至比沒有執行緒池的10k連線更好。執行緒池允許Percona Server更有效地管理資源並提供更好的響應時間。
結論
MySQL可以實現100k連線,我相信我們可以更進一步。有三個元件可以實現此目的:
- Percona Server中的執行緒池
- 正確調整網路限制
- 在伺服器盒上使用多個IP地址(每個約60k連線一個IP地址)
完整my.cnf:
[mysqld] datadir {{ mysqldir }} ssl=0 skip-log-bin log-error=error.log # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 character_set_server=latin1 collation_server=latin1_swedish_ci skip-character-set-client-handshake innodb_undo_log_truncate=off # general table_open_cache = 200000 table_open_cache_instances=64 back_log=3500 max_connections=110000 # files innodb_file_per_table innodb_log_file_size=15G innodb_log_files_in_group=2 innodb_open_files=4000 # buffers innodb_buffer_pool_size= 40G innodb_buffer_pool_instances=8 innodb_log_buffer_size=64M # tune innodb_doublewrite= 1 innodb_thread_concurrency=0 innodb_flush_log_at_trx_commit= 0 innodb_flush_method=O_DIRECT_NO_FSYNC innodb_max_dirty_pages_pct=90 innodb_max_dirty_pages_pct_lwm=10 innodb_lru_scan_depth=2048 innodb_page_cleaners=4 join_buffer_size=256K sort_buffer_size=256K innodb_use_native_aio=1 innodb_stats_persistent = 1 innodb_spin_wait_delay=96 innodb_adaptive_flushing = 1 innodb_flush_neighbors = 0 innodb_read_io_threads = 16 innodb_write_io_threads = 16 innodb_io_capacity=1500 innodb_io_capacity_max=2500 innodb_purge_threads=4 innodb_adaptive_hash_index=0 max_prepared_stmt_count=1000000 innodb_monitor_enable = '%' performance_schema = ON |
相關文章
- percona資料庫效能部落格好文章資料庫
- 部落格資料庫要連線Elasticsearch,使用MySQL還是Mong資料庫ElasticsearchMySql
- 部落格資料庫要連線Elasticsearch,使用MySQL還是MongoDB更合理資料庫ElasticsearchMySqlMongoDB
- 部落格連結—Oracle資料庫類Oracle資料庫
- 連線mysql資料庫MySql資料庫
- 連線資料庫-mysql資料庫MySql
- 用Navicat連線資料庫-資料庫連線(MySQL演示)資料庫MySql
- django | 連線mysql資料庫DjangoMySql資料庫
- 如何連線MySQL資料庫MySql資料庫
- pycharm連線MySQL資料庫PyCharmMySql資料庫
- Mysql資料庫表連線MySql資料庫
- PHP連線MySql資料庫PHPMySql資料庫
- mysql資料庫連線(MySQLdb)MySql資料庫
- Weka 連線MySQL資料庫MySql資料庫
- java連線mysql資料庫JavaMySql資料庫
- Ruby連線MySQL資料庫MySql資料庫
- 【譯】MySQL挑戰:建立10萬連線MySql
- (轉)PHP連線資料庫之PHP連線MYSQL資料庫程式碼PHP資料庫MySql
- Django 2連線MySQL資料庫DjangoMySql資料庫
- mysql資料庫怎麼連線MySql資料庫
- 遠端連線mysql資料庫MySql資料庫
- 【JavaWeb】JDBC連線MySQL資料庫JavaWebJDBCMySql資料庫
- 用thinkphp連線mysql資料庫PHPMySql資料庫
- Python連線MySQL資料庫PythonMySql資料庫
- 使用cmd連線mysql資料庫MySql資料庫
- 成為MySQL DBA 部落格系列-資料庫升級MySql資料庫
- python資料插入連線MySQL資料庫PythonMySql資料庫
- Django使用pymysql連線MySQL資料庫DjangoMySql資料庫
- MySql資料庫連線池專題MySql資料庫
- 使用PETAPOCO連線MYSQL資料庫MySql資料庫
- 精PHP與MYSQL資料庫連線PHPMySql資料庫
- mysql資料庫連線池配置教程MySql資料庫
- PHP連線、查詢MySQL資料庫PHPMySql資料庫
- Pycharm 怎麼連線 MySQL 資料庫PyCharmMySql資料庫
- Spring JPA資料庫連線MySQLSpring資料庫MySql
- 使用ABP EntityFramework連線MySQL資料庫FrameworkMySql資料庫
- R語言連線資料庫(MySQL)R語言資料庫MySql
- MFC 使用VS 連線 MySQL資料庫MySql資料庫