1.开源项目|高性能内存分配库mimalloc
2.ä¼åmysql å¤å¤§å
å centos6
3.在英特尔 CPU 上微调 Stable Diffusion 模型
4.Spring Boot引起的源码“堆外内存泄漏”排查及经验总结
开源项目|高性能内存分配库mimalloc
mimalloc
开源内存分配库,微软研究院年发布,源码旨在提供高性能内存管理解决方案。源码
使用方法如下:
1. 克隆代码库至本地。源码
2. 编译代码。源码
3. 将头文件复制至系统目录,源码tomcat 源码书籍如:
4. 编译项目时链接mimalloc。源码
尝试直接使用mimalloc,源码无需编译:
配置环境变量。源码
mimalloc特点:
1. 简洁高效,源码核心代码量少于行。源码
2. 性能显著优于其他内存分配库,源码如:mi(mimalloc)、源码tc(tcmalloc)、源码je(jemalloc)等。源码
3. 支持多线程。
架构:
mimalloc设计中,每个线程拥有专属堆,线程在分配内存时从各自堆进行。堆中包含多个分段,每个分段对应多个页面,内存分配在页面上进行。
free列表操作代码。
源码实现:
1. malloc函数实现
2. free函数实现
参考资料:
[1] cnblogs.com/linkwk7/p/1...
[2] github.com/microsoft/mi...
[3] cnblogs.com/linkwk7/p/1...
ä¼åmysql å¤å¤§å å centos6
ä¸ãmysqlçä¼åæè·¯
mysqlçä¼åå为两æ¹é¢ï¼
1. æå¡å¨ä½¿ç¨åçä¼å
2. æå¡ä½¿ç¨ä¸çä¼å
äºãmysqlçåºç¡ä¼åæ¥éª¤
1. 硬件级ä¼å
ï¼1ï¼. æ好mysqlèªå·±ä½¿ç¨ä¸å°ç©çæå¡å¨
ï¼2ï¼. å ååCPUæ¹é¢ï¼æ ¹æ®éæ±ç»äºmysqlæå¡å¨è¶³å¤å¤§çå åå足å¤å¤çCPUæ ¸æ°
(3). é¿å 使ç¨Swap交æ¢ååºâ交æ¢æ¶ä»ç¡¬ç读åçå®çé度å¾æ ¢ï¼æçDBAå®è£ ç³»ç»æ¶å°±ä¸è£ swapååº
ï¼4ï¼. å¦ææ¯mysql主åºï¼ç¡¬çå¯ä»¥éç¨æ¯è¾å¥½çé«é硬çï¼ç³»ç»ç¨SSDåºæ硬çï¼æ°æ®çç¨sasæ¿ä»£sata硬çï¼å°æä½ç³»ç»åæ°æ®ååºåå¼
ï¼5ï¼. mysql产ççæ¥å¿ä¸æ°æ®åºä¹æ¾å°ä¸åçç£çååºä¸é¢
ï¼6ï¼. mysqlæ°æ®åºç¡¬çæ ¼å¼åæ¶ï¼å¯ä»¥æå®æ´å°ç硬çå
ï¼7ï¼. å ³äºåRAIDæ¹é¢ï¼ä¸»åºå°½éåæRAIDï¼æ¢æé«äºæ°æ®ç读åé度ä¹æå°äºæ°æ®çå®å ¨æ§
ï¼8). æå¡å¨å线åçµï¼ä¿éæå¡å¨è¿è¡ç¨³å®ï¼ä¸ä¼å 为çªç¶æçµå½±åä¸å¡åæåç£çæ°æ®
2. mysqlæ°æ®åºè®¾è®¡ä¼å
ï¼1). æ ¹æ®éæ±éæ©æ£ç¡®çåå¨å¼æï¼æ¯å¦è¯´è¯»çç¹å«çå°±ç¨MySAM,å¦æ对äºå¡æ§è¦æ±é«å°±ç¨InnoDB
(2). 设置åççå段类ååå段é¿åº¦,æ¯å¦è¯´ä½ è¿ä¸ªå段就å¤ä¸ªåæ®µä½ è®¾ç½®æVARCHAR()å°±æ¯å¯¹ç£ç空é´ç浪费
ï¼3ï¼. é»è®¤å¼å°½å¯è½çä½¿ç¨ NOT NULLï¼å¦æ空å¼å¤ªå¤å¯¹mysqlçæ¥è¯¢ä¼æå½±åï¼å°¤å ¶æ¯å¨æ¥è¯¢è¯å¥ç¼åä¸é¢
ï¼4ï¼. å°½éå°ç使ç¨VARCHARï¼TEXTï¼BLOBè¿ä¸ä¸ªå段
ï¼5ï¼. æ·»å éå½ç´¢å¼(index) [åç§: æ®éç´¢å¼ã主é®ç´¢å¼ãå¯ä¸ç´¢å¼uniqueãå ¨æç´¢å¼]
ï¼6ï¼. ä¸è¦æ»¥ç¨ç´¢å¼ï¼å¤§è¡¨ç´¢å¼ï¼å°è¡¨ä¸ç´¢å¼
ï¼7ï¼. 表ç设计åçå(符å3NF)
3. mysqlé ç½®åæ°çä¼å
è¿éæ¯mysql5.5çæ¬çé ç½®æ件
vi my.cnf
[client]
port = #mysql客æ·ç«¯è¿æ¥æ¶çé»è®¤ç«¯å£
socket = /tmp/mysql.sock #ä¸mysqlæå¡å¨æ¬å°éä¿¡æ使ç¨çsocketæ件路å¾
default-character-set = utf8 #æå®é»è®¤å符é为utf8
[mysql]
no-auto-rehash #auto-rehashæ¯èªå¨è¡¥å ¨çææï¼å°±åæ们å¨linuxå½ä»¤è¡éè¾å ¥å½ä»¤çæ¶åï¼ä½¿ç¨tabé®çåè½æ¯ä¸æ ·çï¼è¿éæ¯é»è®¤çä¸èªå¨è¡¥å ¨
default-character-set = utf8 #æå®é»è®¤å符é为utf8
[mysqld]
user = mysql
port =
character-set-server = utf8 #设置æå¡å¨ç«¯çå符ç¼ç
socket = /tmp/mysql.sock
basedir = /application/mysql
datadir = /mysqldata
skip-locking #é¿å MySQLçå¤é¨éå®ï¼åå°åºéå çå¢å¼ºç¨³å®æ§ã
open_files_limit = #MySQLæå¼çæ件æ述符éå¶ï¼é»è®¤æå°;å½open_files_limit没æ被é ç½®çæ¶åï¼æ¯è¾max_connections*5åulimit -nçå¼ï¼åªä¸ªå¤§ç¨åªä¸ªï¼å½open_file_limit被é ç½®çæ¶åï¼æ¯è¾open_files_limitåmax_connections*5çå¼ï¼åªä¸ªå¤§ç¨åªä¸ªã
back_log = #back_logåæ°çå¼æåºå¨MySQLææ¶åæ¢ååºæ°è¯·æ±ä¹åççæ¶é´å å¤å°ä¸ªè¯·æ±å¯ 以被åå¨å æ ä¸ã å¦æç³»ç»å¨ä¸ä¸ªçæ¶é´å æå¾å¤è¿æ¥ï¼åéè¦å¢å¤§è¯¥åæ°çå¼ï¼è¯¥åæ°å¼æå®å°æ¥çTCP/IPè¿æ¥ç侦å¬éåç大å°ãä¸åçæä½ç³»ç»å¨è¿ä¸ªéå大å°ä¸æå®èª å·±çéå¶ã è¯å¾è®¾back_logé«äºä½ çæä½ç³»ç»çéå¶å°æ¯æ æçãé»è®¤å¼ä¸ºã对äºLinuxç³»ç»æ¨è设置为å°äºçæ´æ°ã
max_connections = #MySQLçæ大è¿æ¥æ°ï¼å¦ææå¡å¨ç并åè¿æ¥è¯·æ±éæ¯è¾å¤§ï¼å»ºè®®è°é«æ¤å¼ï¼ä»¥å¢å 并è¡è¿æ¥æ°éï¼å½ç¶è¿å»ºç«å¨æºå¨è½æ¯æçæ åµä¸ï¼å 为å¦æè¿æ¥æ°è¶å¤ï¼ ä»äºMySQLä¼ä¸ºæ¯ä¸ªè¿æ¥æä¾è¿æ¥ç¼å²åºï¼å°±ä¼å¼éè¶å¤çå åï¼æ以è¦éå½è°æ´è¯¥å¼ï¼ä¸è½ç²ç®æé«è®¾å¼ãå¯ä»¥è¿âconn%âéé 符æ¥çå½åç¶æçè¿æ¥ æ°éï¼ä»¥å®å¤ºè¯¥å¼ç大å°ã
max_connect_errors = #对äºåä¸ä¸»æºï¼å¦ææè¶ åºè¯¥åæ°å¼ä¸ªæ°çä¸æé误è¿æ¥ï¼å该主æºå°è¢«ç¦æ¢è¿æ¥ãå¦é对该主æºè¿è¡è§£ç¦ï¼æ§è¡ï¼FLUSH HOSTã
table_cache = #ç©çå åè¶å¤§,设置就è¶å¤§.é»è®¤ä¸º,è°å°-æä½³
external-locking = FALSE #使ç¨âskip-external-locking MySQLé项以é¿å å¤é¨éå®ã该é项é»è®¤å¼å¯
max_allowed_packet =8M #设置æ大å ,éå¶serveræ¥åçæ°æ®å 大å°ï¼é¿å è¶ é¿SQLçæ§è¡æé®é¢ é»è®¤å¼ä¸ºMï¼å½MySQL客æ·ç«¯æmysqldæå¡å¨æ¶å°å¤§äºmax_allowed_packetåèçä¿¡æ¯å æ¶ï¼å°ååºâä¿¡æ¯å è¿å¤§âé误ï¼å¹¶å ³éè¿æ¥ã对äºæäºå®¢æ·ç«¯ï¼å¦æéä¿¡ä¿¡æ¯å è¿å¤§ï¼å¨æ§è¡æ¥è¯¢æé´ï¼å¯è½ä¼éâ丢失ä¸MySQLæå¡å¨çè¿æ¥âé误ãé»è®¤å¼Mã
sort_buffer_size = 6M #ç¨äºè¡¨é´å ³èç¼åç大å°ï¼æ¥è¯¢æåºæ¶æè½ä½¿ç¨çç¼å²åºå¤§å°ã注æï¼è¯¥åæ°å¯¹åºçåé å åæ¯æ¯è¿æ¥ç¬å ï¼å¦ææ个è¿æ¥ï¼é£ä¹å®é åé çæ»å ±æåºç¼å²åºå¤§å°ä¸º à 6 ï¼ MBãæ以ï¼å¯¹äºå åå¨4GBå·¦å³çæå¡å¨æ¨è设置为6-8Mã
join_buffer_size = 6M #èåæ¥è¯¢æä½æè½ä½¿ç¨çç¼å²åºå¤§å°ï¼åsort_buffer_sizeä¸æ ·ï¼è¯¥åæ°å¯¹åºçåé å åä¹æ¯æ¯è¿æ¥ç¬äº«ã
thread_cache_size = #æå¡å¨çº¿ç¨ç¼åè¿ä¸ªå¼è¡¨ç¤ºå¯ä»¥éæ°å©ç¨ä¿åå¨ç¼åä¸çº¿ç¨çæ°é,å½æå¼è¿æ¥æ¶å¦æç¼åä¸è¿æ空é´,é£ä¹å®¢æ·ç«¯ç线ç¨å°è¢«æ¾å°ç¼åä¸,å¦æ线ç¨éæ°è¢«è¯·æ±ï¼ é£ä¹è¯·æ±å°ä»ç¼åä¸è¯»å,å¦æç¼åä¸æ¯ç©ºçæè æ¯æ°ç请æ±ï¼é£ä¹è¿ä¸ªçº¿ç¨å°è¢«éæ°å建,å¦ææå¾å¤æ°ç线ç¨ï¼å¢å è¿ä¸ªå¼å¯ä»¥æ¹åç³»ç»æ§è½.éè¿æ¯è¾ Connections å Threads_created ç¶æçåéï¼å¯ä»¥çå°è¿ä¸ªåéçä½ç¨
thread_concurrency = 8 #设置thread_concurrencyçå¼çæ£ç¡®ä¸å¦, 对mysqlçæ§è½å½±åå¾å¤§, å¨å¤ä¸ªcpu(æå¤æ ¸)çæ åµä¸ï¼é误设置äºthread_concurrencyçå¼, ä¼å¯¼è´mysqlä¸è½å åå©ç¨å¤cpu(æå¤æ ¸), åºç°åä¸æ¶å»åªè½ä¸ä¸ªcpu(ææ ¸)å¨å·¥ä½çæ åµãthread_concurrencyåºè®¾ä¸ºCPUæ ¸æ°ç2å. æ¯å¦æä¸ä¸ªåæ ¸çCPU, é£ä¹thread_concurrencyçåºè¯¥ä¸º4; 2个åæ ¸çcpu, thread_concurrencyçå¼åºä¸º8ï¼å±éç¹ä¼ååæ°
query_cache_size = 2M #æå®MySQLæ¥è¯¢ç¼å²åºç大å°ï¼å¨æ°æ®åºåå ¥éææ¯æ´æ°éä¹æ¯è¾å¤§çç³»ç»ï¼è¯¥åæ°ä¸éååé è¿å¤§ãèä¸å¨é«å¹¶åï¼åå ¥é大çç³»ç»ï¼å»ºç³»æ该åè½ç¦æã
query_cache_limit = 1M #é»è®¤æ¯4KBï¼è®¾ç½®å¼å¤§å¯¹å¤§æ°æ®æ¥è¯¢æ好å¤ï¼ä½å¦æä½ çæ¥è¯¢é½æ¯å°æ°æ®æ¥è¯¢ï¼å°±å®¹æé æå åç¢çå浪费
query_cache_min_res_unit = 2k #MySQLåæ°ä¸query_cache_min_res_unitæ¥è¯¢ç¼åä¸çåæ¯ä»¥è¿ä¸ªå¤§å°è¿è¡åé çï¼ä½¿ç¨ä¸é¢çå ¬å¼è®¡ç®æ¥è¯¢ç¼åçå¹³å大å°ï¼æ ¹æ®è®¡ç®ç»æ设置è¿ä¸ªåéï¼MySQLå°±ä¼æ´ææå°ä½¿ç¨æ¥è¯¢ç¼åï¼ç¼åæ´å¤çæ¥è¯¢ï¼åå°å åç浪费ã
default_table_type = InnoDB #é»è®¤è¡¨çå¼æ为InnoDB
thread_stack = K #éå®ç¨äºæ¯ä¸ªæ°æ®åºçº¿ç¨çæ 大å°ãé»è®¤è®¾ç½®è¶³ä»¥æ»¡è¶³å¤§å¤æ°åºç¨transaction_isolation = READ-COMMITTED #设å®é»è®¤çäºå¡é离级å«.å¯ç¨ç级å«å¦ä¸:
READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE,1.READ UNCOMMITTED-读æªæ交2.READ COMMITTE-读已æ交3.REPEATABLE READ -å¯éå¤è¯»4.SERIALIZABLE -串è¡
tmp_table_size = M #tmp_table_size çé»è®¤å¤§å°æ¯ Mãå¦æä¸å¼ 临æ¶è¡¨è¶ åºè¯¥å¤§å°ï¼MySQL产çä¸ä¸ª The table tbl_name is full å½¢å¼çé误ï¼å¦æä½ åå¾å¤é«çº§ GROUP BY æ¥è¯¢ï¼å¢å tmp_table_size å¼ã
max_heap_table_size = M #å å表ï¼å å表ä¸æ¯æäºå¡ï¼å å表使ç¨åå¸æ£åç´¢å¼ææ°æ®ä¿åå¨å åä¸ï¼å æ¤å ·ææå¿«çé度ï¼éåç¼åä¸å°åæ°æ®åºï¼ä½æ¯ä½¿ç¨ä¸åå°ä¸äºéå¶
long_query_time = 1 #è®°å½æ¶é´è¶ è¿1ç§çæ¥è¯¢è¯å¥
log_long_format #
log-error = /logs/error.log #å¼å¯mysqlé误æ¥å¿ï¼è¯¥é项æå®mysqldä¿åé误æ¥å¿æ件çä½ç½®
log-slow-queries = /logs/slow.log #æ ¢æ¥è¯¢æ¥å¿æ件路å¾
pid-file = /pids/mysql.pid
log-bin = /binlog/mysql-bin #binlogæ¥å¿ä½ç½®ä»¥åbinlogçå称
relay-log = /relaylog/relay-bin #relaylogæ¥å¿ä½ç½®ä»¥å称
binlog_cache_size = 1M #binlog_cache_size å°±æ¯æ»¡è¶³ä¸¤ç¹çï¼ä¸ä¸ªäºå¡ï¼å¨æ²¡ææ交ï¼uncommittedï¼çæ¶åï¼äº§ççæ¥å¿ï¼è®°å½å°Cacheä¸ï¼çå°äºå¡æ交ï¼committedï¼éè¦æ交çæ¶åï¼åææ¥å¿æä¹ åå°ç£çï¼é»è®¤æ¯Kã
max_binlog_cache_size = M #binlogç¼åæ大使ç¨çå å
max_binlog_size = 2M #ä¸ä¸ªbinlogæ¥å¿ç大å°
expire_logs_days = 7 #ä¿ç7天çbinlog
key_buffer_size = M #ç´¢å¼ç¼å大å°: å®å³å®äºæ°æ®åºç´¢å¼å¤ççé度ï¼å°¤å ¶æ¯ç´¢å¼è¯»çé度
read_buffer_size = M #MySqlè¯»å ¥ç¼å²åºå¤§å°ã对表è¿è¡é¡ºåºæ«æç请æ±å°åé ä¸ä¸ªè¯»å ¥ç¼å²åºï¼MySqlä¼ä¸ºå®åé ä¸æ®µå åç¼å²åºãread_buffer_sizeåéæ§å¶è¿ä¸ç¼å²åºç大å°ãå¦æ对表ç顺åºæ«æ请æ±é常é¢ç¹ï¼å¹¶ä¸ä½ 认为é¢ç¹æ«æè¿è¡å¾å¤ªæ ¢ï¼å¯ä»¥éè¿å¢å 该åéå¼ä»¥åå åç¼å²åºå¤§å°æé«å ¶æ§è½
read_rnd_buffer_size = 2M #MySQLçéæºè¯»ç¼å²åºå¤§å°ãå½æä»»æ顺åºè¯»åè¡æ¶(ä¾å¦ï¼æç §æåºé¡ºåº)ï¼å°åé ä¸ä¸ªéæºè¯»ç¼ååºãè¿è¡æåºæ¥è¯¢æ¶ï¼MySQLä¼é¦å æ«æä¸é该ç¼å²ï¼ä»¥é¿å ç£çæç´¢ï¼æé«æ¥è¯¢é度ï¼å¦æéè¦æåºå¤§éæ°æ®ï¼å¯éå½è°é«è¯¥å¼ãä½MySQLä¼ä¸ºæ¯ä¸ªå®¢æ·è¿æ¥åæ¾è¯¥ç¼å²ç©ºé´ï¼æ以åºå°½ééå½è®¾ç½®è¯¥å¼ï¼ä»¥é¿å å åå¼éè¿å¤§
bulk_insert_buffer_size = 1M #æ¹éæå ¥æ°æ®ç¼å大å°ï¼å¯ä»¥æææé«æå ¥æçï¼é»è®¤ä¸º8M
myisam_sort_buffer_size = 1M #MyISAM表åçååæ¶éæ°æåºæéçç¼å²
myisam_max_sort_file_size = G #MySQLé建索å¼æ¶æå 许çæ大临æ¶æ件çå¤§å° (å½ REPAIR, ALTER TABLE æè LOAD DATA INFILE). å¦ææ件大å°æ¯æ¤å¼æ´å¤§,ç´¢å¼ä¼éè¿é®å¼ç¼å²å建(æ´æ ¢)
myisam_repair_threads = 1 #å¦æä¸ä¸ªè¡¨æ¥æè¶ è¿ä¸ä¸ªç´¢å¼, MyISAM å¯ä»¥éè¿å¹¶è¡æåºä½¿ç¨è¶ è¿ä¸ä¸ªçº¿ç¨å»ä¿®å¤ä»ä»¬.è¿å¯¹äºæ¥æå¤ä¸ªCPU以å大éå åæ åµçç¨æ·,æ¯ä¸ä¸ªå¾å¥½çéæ©.
myisam_recover #èªå¨æ£æ¥åä¿®å¤æ²¡æéå½å ³éç MyISAM 表
lower_case_table_names = 1 #让mysqlä¸åºå大å°å
skip-name-resolve #ç¦ç¨DNS解æï¼è¿æ¥é度ä¼å¿«å¾å¤ãä¸è¿ï¼è¿æ ·çè¯å°±ä¸è½å¨MySQLçææ表ä¸ä½¿ç¨ä¸»æºåäºèåªè½ç¨ipæ ¼å¼ã
#slave-skip-errors = , #è¿æ¯é填项让slaveåºè·³è¿åªäºé误继ç»åæ¥
#replicate-ignore-db=mysql #éå¡«ï¼åæ¥æ¶ååªä¸ªæ°æ®åºä¸åæ¥è®¾ç½®
server-id = 1
innodb_additional_mem_pool_size = 4M #InnoDB åå¨çæ°æ®ç®å½ä¿¡æ¯åå ¶å®å é¨æ°æ®ç»æçå åæ± å¤§å°ãåºç¨ç¨åºéç表è¶å¤ï¼ä½ éè¦å¨è¿éåé è¶å¤çå åï¼é»è®¤æ¯2M
innodb_buffer_pool_size = M #è¿å¯¹Innodb表æ¥è¯´é常éè¦ãInnodbç¸æ¯MyISAM表对ç¼å²æ´ä¸ºææãMyISAMå¯ä»¥å¨é» 认ç key_buffer_size 设置ä¸è¿è¡çå¯ä»¥ï¼ç¶èInnodbå¨é»è®¤ç 设置ä¸å´è·èçä¼¼çãç±äºInnodbææ°æ®åç´¢å¼é½ç¼åèµ·æ¥ï¼æ éçç»æä½ç³»ç»å¤ªå¤çå åï¼å æ¤å¦æåªéè¦ç¨Innodbçè¯åå¯ä»¥è®¾ç½®å®é«è¾¾ -% çå¯ç¨å åãä¸äºåºç¨äº key_buffer çè§åæ â å¦æä½ çæ°æ®éä¸å¤§ï¼å¹¶ä¸ä¸ä¼æ´å¢ï¼é£ä¹æ éæ innodb_buffer_pool_size 设置ç太大äº
innodb_file_io_threads = 4 #æ件IOç线ç¨æ°ï¼ä¸è¬ä¸º 4
innodb_thread_concurrency = 8 #ä½ çæå¡å¨CPUæå 个就设置为å ,建议ç¨é»è®¤ä¸è¬ä¸º8
innodb_flush_log_at_trx_commit = 2 #é»è®¤ä¸º1ï¼å¦æå°æ¤åæ°è®¾ç½®ä¸º1ï¼å°å¨æ¯æ¬¡æ交äºå¡åå°æ¥å¿åå ¥ç£çã为æä¾æ§è½ï¼å¯ä»¥è®¾ç½®ä¸º0æ2ï¼ä½è¦æ¿æ å¨åçæ éæ¶ä¸¢å¤±æ°æ®çé£é©ã设置为0表示äºå¡æ¥å¿åå ¥æ¥å¿æ件ï¼èæ¥å¿æ件æ¯ç§å·æ°å°ç£çä¸æ¬¡ã设置为2表示äºå¡æ¥å¿å°å¨æ交æ¶åå ¥æ¥å¿ï¼ä½æ¥å¿æ件æ¯æ¬¡å·æ°å°ç£çä¸æ¬¡ã
innodb_log_buffer_size = 2M #æ¤åæ°ç¡®å®äºæ¥å¿æ件æç¨çå å大å°ï¼ä»¥M为åä½ãç¼å²åºæ´å¤§è½æé«æ§è½ï¼ä½æå¤çæ éå°ä¼ä¸¢å¤±æ°æ®.MySQLå¼å人å建议设置为1ï¼8Mä¹é´
innodb_log_file_size = 4M #æ¤åæ°ç¡®å®æ°æ®æ¥å¿æ件ç大å°ï¼ä»¥M为åä½ï¼æ´å¤§ç设置å¯ä»¥æé«æ§è½ï¼ä½ä¹ä¼å¢å æ¢å¤æ éæ°æ®åºæéçæ¶é´
innodb_log_files_in_group = 3 #为æé«æ§è½ï¼MySQLå¯ä»¥ä»¥å¾ªç¯æ¹å¼å°æ¥å¿æ件åå°å¤ä¸ªæ件ãæ¨è设置为3M
innodb_max_dirty_pages_pct = #Buffer_Poolä¸Dirty_Pageæå çæ°éï¼ç´æ¥å½±åInnoDBçå ³éæ¶é´ãåæ° innodb_max_dirty_pages_pctå¯ä»¥ç´æ¥æ§å¶äºDirty_Pageå¨Buffer_Poolä¸æå çæ¯çï¼èä¸å¹¸è¿çæ¯ innodb_max_dirty_pages_pctæ¯å¯ä»¥å¨ææ¹åçãæ以ï¼å¨å ³éInnoDBä¹åå è°å°ï¼å¼ºå¶æ°æ®åFlushä¸æ®µæ¶é´ï¼åè½å¤å¤§å¤§ç¼©çMySQLå ³éçæ¶é´ã
innodb_lock_wait_timeout = #InnoDB æå ¶å ç½®çæ»éæ£æµæºå¶ï¼è½å¯¼è´æªå®æçäºå¡åæ»ãä½æ¯ï¼å¦æç»åInnoDB使ç¨MyISAMçlock tables è¯å¥æ第ä¸æ¹äºå¡å¼æ,åInnoDBæ æ³è¯å«æ»éã为æ¶é¤è¿ç§å¯è½æ§ï¼å¯ä»¥å°innodb_lock_wait_timeout设置为ä¸ä¸ªæ´æ°å¼ï¼æ示 MySQLå¨å è®¸å ¶ä»äºå¡ä¿®æ¹é£äºæç»åäºå¡åæ»çæ°æ®ä¹åè¦çå¾ å¤é¿æ¶é´(ç§æ°)
innodb_file_per_table = 0 #ç¬äº«è¡¨ç©ºé´ï¼å ³éï¼
[mysqldump]
quick
max_allowed_packet = M
4. æ¶æä¼å
ï¼1ï¼. å端ç¨memcachedï¼redisçç¼ååæ æ°æ®åºåå
ï¼2ï¼. æ°æ®åºè¯»åå离ï¼è´è½½åè¡¡
ï¼3ï¼. æ°æ®åºååºå表
ï¼4ï¼. åå¨å¯éååå¸å¼
5. åæä¼å
主è¦æ¯å¤è§å¯ï¼åæå°±æ¯ç»´æ¤å·¥ä½äºï¼è§å¯æå¡å¨è´è½½æ¯éè¦æ·»å 硬件äºï¼è¿æ¯æè¯å¥æé®é¢åï¼è¿æ¯åæ°è¦ä¿®æ¹äºã
6. æ¥è¯¢ä¼åï¼ææå«äººçï¼
. 使ç¨æ ¢æ¥è¯¢æ¥å¿å»åç°æ ¢æ¥è¯¢ã
. 使ç¨æ§è¡è®¡åå»å¤ææ¥è¯¢æ¯å¦æ£å¸¸è¿è¡ã
. æ»æ¯å»æµè¯ä½ çæ¥è¯¢ççæ¯å¦ä»ä»¬è¿è¡å¨æä½³ç¶æä¸ âä¹ èä¹ ä¹æ§è½æ»ä¼ååã
. é¿å å¨æ´ä¸ªè¡¨ä¸ä½¿ç¨count(*),å®å¯è½éä½æ´å¼ 表ã
. 使æ¥è¯¢ä¿æä¸è´ä»¥ä¾¿åç»ç¸ä¼¼çæ¥è¯¢å¯ä»¥ä½¿ç¨æ¥è¯¢ç¼åã
. å¨éå½çæ å½¢ä¸ä½¿ç¨GROUP BYèä¸æ¯DISTINCTã
. å¨WHERE, GROUP BYåORDER BYåå¥ä¸ä½¿ç¨æç´¢å¼çåã
. ä¿æç´¢å¼ç®å,ä¸å¨å¤ä¸ªç´¢å¼ä¸å å«åä¸ä¸ªåã
. ææ¶åMySQLä¼ä½¿ç¨é误çç´¢å¼,对äºè¿ç§æ åµä½¿ç¨USE INDEXã
. æ£æ¥ä½¿ç¨SQL_MODE=STRICTçé®é¢ã
. 对äºè®°å½æ°å°äº5çç´¢å¼å段ï¼å¨UNIONçæ¶å使ç¨LIMITä¸æ¯æ¯ç¨OR.
. ä¸ºäº é¿å å¨æ´æ°åSELECTï¼ä½¿ç¨INSERT ON DUPLICATE KEYæè INSERT IGNORE ,ä¸è¦ç¨UPDATEå»å®ç°ã
. ä¸è¦ä½¿ç¨ MAX,使ç¨ç´¢å¼å段åORDER BYåå¥ã
. é¿å 使ç¨ORDER BY RAND().
ãLIMIT Mï¼Nå®é ä¸å¯ä»¥åç¼æ¥è¯¢å¨æäºæ åµä¸ï¼æèå¶å°ä½¿ç¨ã
ãå¨WHEREåå¥ä¸ä½¿ç¨UNION代æ¿åæ¥è¯¢ã
ã对äºUPDATESï¼æ´æ°ï¼ï¼ä½¿ç¨ SHARE MODEï¼å ±äº«æ¨¡å¼ï¼ï¼ä»¥é²æ¢ç¬å éã
ãå¨éæ°å¯å¨çMySQLï¼è®°å¾æ¥æ¸©æä½ çæ°æ®åºï¼ä»¥ç¡®ä¿æ¨çæ°æ®å¨å ååæ¥è¯¢é度快ã
ã使ç¨DROP TABLEï¼CREATE TABLE DELETE FROMä»è¡¨ä¸å é¤æææ°æ®ã
ãæå°åçæ°æ®å¨æ¥è¯¢ä½ éè¦çæ°æ®ï¼ä½¿ç¨*æ¶è大éçæ¶é´ã
ãèèæä¹ è¿æ¥ï¼èä¸æ¯å¤ä¸ªè¿æ¥ï¼ä»¥åå°å¼éã
ãåºåæ¥è¯¢ï¼å æ¬ä½¿ç¨æå¡å¨ä¸çè´è½½ï¼ææ¶ä¸ä¸ªç®åçæ¥è¯¢å¯ä»¥å½±åå ¶ä»æ¥è¯¢ã
ãå½è´è½½å¢å æ¨çæå¡å¨ä¸ï¼ä½¿ç¨SHOW PROCESSLISTæ¥çæ ¢çåæé®é¢çæ¥è¯¢ã
ãå¨å¼åç¯å¢ä¸äº§ççéåæ°æ®ä¸ æµè¯çææå¯ççæ¥è¯¢ã
在英特尔 CPU 上微调 Stable Diffusion 模型
扩散模型,一种能够根据文本提示生成逼真图像的能力,显著推动了生成式人工智能的普及。这些模型广泛应用于数据合成和内容创建等领域,喷码机追踪源码Hugging Face Hub 上拥有超过5千个预训练的文生图模型。结合Diffusers库,构建图像生成工作流或实验不同的图像生成流程变得极为简便。
微调扩散模型以满足特定业务需求的图像生成,通常依赖于GPU。然而,这一情况正在发生变化。英特尔推出了代号为Sapphire Rapids的第四代至强CPU,其中包含英特尔先进矩阵扩展(AMX),专门用于加速深度学习工作负载。在之前的博文中,我们已经展示了AMX的优势,包括微调NLP transformer模型、对NLP transformer模型进行推理以及对Stable Diffusion模型进行推理。
本文将展示如何在英特尔第四代至强CPU集群上微调Stable Diffusion模型。我们采用文本逆向(Textual Inversion)技术进行微调,仅需少量训练样本即可有效调整模型。使用5个样本即可实现。
配置集群时,我们利用英特尔开发者云提供的服务器。这些服务器配置了英特尔第四代至强CPU,每颗CPU包含个物理核和个线程。通过nodefile文件,我们管理了服务器IP地址,其中第一行指为主服务器。
分布式训练要求主节点与其他节点之间实现无密码SSH通信。linux cdwriter源码设置无密码SSH,参考相关文章步骤操作。
搭建运行环境并安装所需软件,包括英特尔优化库如oneCCL和Intel Extension for PyTorch(IPEX),以利用Sapphire Rapids的硬件加速功能。此外,我们安装了高性能内存分配库libtcmalloc及其软件依赖项gperftools。
在每个节点上,我们克隆diffusers代码库并进行源码安装。对diffusers/examples/textual_inversion中的微调脚本进行优化,利用IPEX对U-Net和变分自编码器(VAE)模型进行推理优化。
下载训练图像,确保在所有节点上的目录路径一致。微调任务启动后,加速器会自动在节点间建立分布式的训练。
配置微调环境时,使用accelerate库简化分布式训练。在每个节点上运行acclerate config并回答问题。设置环境变量,确保所有节点间的通信。
启动微调,使用mpirun在nodefile列出的节点间建立分布式通信。运行命令训练步,耗时约5分钟。训练过程中的集群状态显示在截图中。
分布式训练中可能出现的fil改源码错误通常包括单节点配置错误,如依赖项缺失或图像位置不同。登录各节点并本地训练可快速定位问题。如果所有节点的训练均成功启动,检查nodefile、环境和mpirun命令。
微调模型后,直接使用diffusers的pipeline加载模型进行图像生成。进一步使用Optimum Intel和OpenVINO对模型进行推理优化。优化后,仅用单颗CPU即可在不到5秒内生成图像。
加载优化后的模型,生成5张不同图像并保存。生成的图像显示模型仅用5张图像就能识别dicoo戴眼镜。对模型进行更多微调,如步,可获得更佳效果。
借助Hugging Face与英特尔的合作,现在能够利用至强CPU服务器生成符合业务需求的高质量图像。CPU不仅比GPU等专用硬件更便宜且易得,还能轻松执行其他任务如Web服务器、数据库等,成为IT基础设施的多功能灵活选择。
入门资源包括:
如有任何疑问或反馈,请访问Hugging Face论坛留言。
Spring Boot引起的“堆外内存泄漏”排查及经验总结
为了更好地实现对项目的管理,我们将组内一个项目迁移到MDP框架(基于Spring Boot),内藏指标源码随后我们就发现系统会频繁报出Swap区域使用量过高的异常。笔者被叫去帮忙查看原因,发现配置了4G堆内内存,但是实际使用的物理内存竟然高达7G,确实不正常。JVM参数配置是“-XX:MetaspaceSize=M -XX:MaxMetaspaceSize=M -XX:+AlwaysPreTouch -XX:ReservedCodeCacheSize=m -XX:InitialCodeCacheSize=m, -Xssk -Xmx4g -Xms4g,-XX:+UseG1GC -XX:G1HeapRegionSize=4M”,实际使用的物理内存如下图所示:
使用Java层面的工具定位内存区域(堆内内存、Code区域或者使用unsafe.allocateMemory和DirectByteBuffer申请的堆外内存)。
笔者在项目中添加-XX:NativeMemoryTracking=detailJVM参数重启项目,使用命令jcmd pid VM.native_memory detail查看到的内存分布如下:
发现命令显示的committed的内存小于物理内存,因为jcmd命令显示的内存包含堆内内存、Code区域、通过unsafe.allocateMemory和DirectByteBuffer申请的内存,但是不包含其他Native Code(C代码)申请的堆外内存。所以猜测是使用Native Code申请内存所导致的问题。
为了防止误判,笔者使用了pmap查看内存分布,发现大量的M的地址;而这些地址空间不在jcmd命令所给出的地址空间里面,基本上就断定就是这些M的内存所导致。
使用系统层面的工具定位堆外内存。
因为已经基本上确定是Native Code所引起,而Java层面的工具不便于排查此类问题,只能使用系统层面的工具去定位问题。
首先,使用了gperftools去定位问题。
从上图可以看出:使用malloc申请的的内存最高到3G之后就释放了,之后始终维持在M-M。笔者第一反应是:难道Native Code中没有使用malloc申请,直接使用mmap/brk申请的?(gperftools原理就使用动态链接的方式替换了操作系统默认的内存分配器(glibc)。)
然后,使用strace去追踪系统调用。
因为使用gperftools没有追踪到这些内存,于是直接使用命令“strace -f -e"brk,mmap,munmap" -p pid”追踪向OS申请内存请求,但是并没有发现有可疑内存申请。
接着,使用GDB去dump可疑内存。
因为使用strace没有追踪到可疑内存申请;于是想着看看内存中的情况。就是直接使用命令gdp -pid pid进入GDB之后,然后使用命令dump memory mem.bin startAddress endAddressdump内存,其中startAddress和endAddress可以从/proc/pid/smaps中查找。然后使用strings mem.bin查看dump的内容,如下:
从内容上来看,像是解压后的JAR包信息。读取JAR包信息应该是在项目启动的时候,那么在项目启动之后使用strace作用就不是很大了。所以应该在项目启动的时候使用strace,而不是启动完成之后。
再次,项目启动时使用strace去追踪系统调用。
项目启动使用strace追踪系统调用,发现确实申请了很多M的内存空间,截图如下:
使用该mmap申请的地址空间在pmap对应如下:
最后,使用jstack去查看对应的线程。
因为strace命令中已经显示申请内存的线程ID。直接使用命令jstack pid去查看线程栈,找到对应的线程栈(注意进制和进制转换)如下:
这里基本上就可以看出问题来了:MCC(美团统一配置中心)使用了Reflections进行扫包,底层使用了Spring Boot去加载JAR。因为解压JAR使用Inflater类,需要用到堆外内存,然后使用Btrace去追踪这个类,栈如下:
然后查看使用MCC的地方,发现没有配置扫包路径,默认是扫描所有的包。于是修改代码,配置扫包路径,发布上线后内存问题解决。
为什么堆外内存没有释放掉呢?
虽然问题已经解决了,但是有几个疑问。带着疑问,直接看了一下 Spring Boot Loader那一块的源码。发现Spring Boot对Java JDK的InflaterInputStream进行了包装并且使用了Inflater,而Inflater本身用于解压JAR包的需要用到堆外内存。而包装之后的类ZipInflaterInputStream没有释放Inflater持有的堆外内存。于是以为找到了原因,立马向Spring Boot社区反馈了这个bug。但是反馈之后,就发现Inflater这个对象本身实现了finalize方法,在这个方法中有调用释放堆外内存的逻辑。也就是说Spring Boot依赖于GC释放堆外内存。
使用jmap查看堆内对象时,发现已经基本上没有Inflater这个对象了。于是就怀疑GC的时候,没有调用finalize。带着这样的怀疑,把Inflater进行包装在Spring Boot Loader里面替换成自己包装的Inflater,在finalize进行打点监控,结果finalize方法确实被调用了。于是又去看了Inflater对应的C代码,发现初始化的使用了malloc申请内存,end的时候也调用了free去释放内存。
此时,怀疑free的时候没有真正释放内存,便把Spring Boot包装的InflaterInputStream替换成Java JDK自带的,发现替换之后,内存问题也得以解决了。
再次看gperftools的内存分布情况,发现使用Spring Boot时,内存使用一直在增加,突然某个点内存使用下降了好多(使用量直接由3G降为M左右)。这个点应该就是GC引起的,内存应该释放了,但是在操作系统层面并没有看到内存变化,那是不是没有释放到操作系统,被内存分配器持有了呢?
继续探究,发现系统默认的内存分配器(glibc 2.版本)和使用gperftools内存地址分布差别很明显,2.5G地址使用smaps发现它是属于Native Stack。内存地址分布如下:
到此,基本上可以确定是内存分配器在捣鬼;搜索了一下glibc M,发现glibc从2.开始对每个线程引入内存池(位机器大小就是M内存),原文如下:
按照文中所说去修改MALLOC_ARENA_MAX环境变量,发现没什么效果。查看tcmalloc(gperftools使用的内存分配器)也使用了内存池方式。
为了验证是内存池搞的鬼,就简单写个不带内存池的内存分配器。使用命令gcc zjbmalloc.c -fPIC -shared -o zjbmalloc.so生成动态库,然后使用export LD_PRELOAD=zjbmalloc.so替换掉glibc的内存分配器。其中代码Demo如下:
通过在自定义分配器当中埋点可以发现实际申请的堆外内存始终在M-M之间,gperftools监控显示内存使用量也是在M-M左右。但是从操作系统角度来看进程占用的内存差别很大(这里只是监控堆外内存)。
使用不同分配器进行不同程度的扫包,占用的内存如下:
为什么自定义的malloc申请M,最终占用的物理内存在1.7G呢?因为自定义内存分配器采用的是mmap分配内存,mmap分配内存按需向上取整到整数个页,所以存在着巨大的空间浪费。通过监控发现最终申请的页面数目在k个左右,那实际上向系统申请的内存等于k * 4k(pagesize) = 2G。
为什么这个数据大于1.7G呢?因为操作系统采取的是延迟分配的方式,通过mmap向系统申请内存的时候,系统仅仅返回内存地址并没有分配真实的物理内存。只有在真正使用的时候,系统产生一个缺页中断,然后再分配实际的物理Page。
整个内存分配的流程如上图所示。MCC扫包的默认配置是扫描所有的JAR包。在扫描包的时候,Spring Boot不会主动去释放堆外内存,导致在扫描阶段,堆外内存占用量一直持续飙升。当发生GC的时候,Spring Boot依赖于finalize机制去释放了堆外内存;但是glibc为了性能考虑,并没有真正把内存归返到操作系统,而是留下来放入内存池了,导致应用层以为发生了“内存泄漏”。所以修改MCC的配置路径为特定的JAR包,问题解决。在发表这篇文章时,发现Spring Boot的最新版本(2.0.5.RELEASE)已经做了修改,在ZipInflaterInputStream主动释放了堆外内存不再依赖GC;所以Spring Boot升级到最新版本,这个问题也可以得到解决。