注意:
1..以下所有讨论都基于mysql 5.5.37版本及官方文档,不保证适用于其他版本。
2.下文中提到的磁盘满,指的是数据文件(数据文件,日志文件,配置文件)所在磁盘分区。
3.由于篇幅问题,最后面的代码部分,只有关键的函数及逻辑判断部分。
前两天同事讨论到一个问题,当mysql从库磁盘满之后,show status及show slave status会被卡住,但其他select操作不受影响,但如果数据库是主库,磁盘满了之后,只有dml会被阻塞,select及show是不会受影响的。于是一群人讨论了一会,最后决定,SMC,以下就是我的结论。
直接查官文档的话,官方作如下表示:
https://dev.mysql.com/doc/refman/5.5/en/full-disk.html
1.实例每分钟检查是否有足够的空间写入。如果已经有空间了,继续执行操作。
2.每十分钟给日志文件写入一条记录,报告磁盘已经写满。
但就我的实验来说,上面的说法存在不少问题。
下面是我对官方文档的测试结果:
1.如果主库上打开binlog,那么当磁盘满之后,每10分钟,数据库会报告一条Disk is full writing './mysql-bin.000001' (Errcode: 28). Waiting for someone to free space... (Expect up to 60 secs delay for server to continue after freeing disk space),也就是说bin log写满了,等待磁盘空间,这与文档描述相同。
2,如果在主库上关闭binlog,当磁盘满了之后,任何插入行为都会失败,报错为[ERROR] ./mysqld: The table 'x' is full,官方文档没有提到这个情况,此处的表x是innodb表。
上面是对主库所在磁盘写满之后,数据库实例的反应,下面讲讲我们遇到的情况:从库磁盘写满之后,show status及show slave status会被卡住,但其他select操作不受影响。
首先,以下是结论:
整个流程涉及3把锁:
1.mi->data_lock
2.LOCK_active_mi
3.LOCK_status
说明如下(以下操作安编号顺序执行):
1.当一个新操作被接收到slave io线程后,如果这时候磁盘写满了,这个写入操作就会被阻塞,然后等待,直到磁盘有空间之后继续写入,这个操作中,会持有mi->data_lock锁,只有操作完成或者操作失败后,这个锁才会被释放,恰好,磁盘满不属于错误,于是操作阻塞,该线程会一直持有mi->data_lock锁。
2.当发起一个show slave status请求的时候,执行的时候,会首先锁住LOCK_active_mi锁,然后锁定mi->data_lock锁,当然,现在的情况下,mi->data_lock不会得到,于是LOCK_active_mi锁就会被该线程持续持有。
3.另外其一个会话发起show global status,执行的时候首先锁定LOCK_status锁,由于show status包括,Slave_heartbeat_period,Slave_open_temp_tables,Slave_received_heartbeats ,Slave_retried_transactions这些状态,于是还需要LOCK_active_mi锁,于是,这个会话也会被阻塞掉。
4.之后如果再另外发起请求,由于LOCK_status已经被锁定,于是所有涉及show status的请求,都会被阻塞到这里。
5.之后所有show slave status请求也都会被阻塞在LOCK_active_mi锁处。
看了以上的结论,是否会想到另外一个操作顺序:磁盘写满-》show status,这种操作的结果是:show status不会被阻塞的。
以下是mysql源代码(5.5.37)涉及到的具体部分:
1.io线程阻塞的相关函数及部分代码
slave.cc
pthread_handler_t handle_slave_io(void *arg)if (queue_event(mi, event_buf, event_len))//写入slave日志函数 { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), "could not queue event from master"); goto err; }
slave.cc
static int queue_event(Master_info* mi,const char* buf, ulong event_len)mysql_mutex_lock(&mi->data_lock);mysql_mutex_lock(log_lock);if (likely(!(rli->relay_log.appendv(buf,event_len,0))))//写入执行函数 { mi->master_log_pos+= inc_pos; DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); rli->relay_log.harvest_bytes_written(&rli->log_space_total); } mysql_mutex_unlock(log_lock);err: mysql_mutex_unlock(&mi->data_lock);
log.cc
bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...){ bool error= 0; DBUG_ENTER("MYSQL_BIN_LOG::appendv"); va_list(args); va_start(args,len); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); mysql_mutex_assert_owner(&LOCK_log); do { if (my_b_append(&log_file,(uchar*) buf,len)) { error= 1; goto err; } bytes_written += len; } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); DBUG_PRINT("info",("max_size: %lu",max_size)); if (flush_and_sync(0))//把日志数据刷入磁盘 goto err; if ((uint) my_b_append_tell(&log_file) > max_size) error= new_file_without_locking();err: if (!error) signal_update(); DBUG_RETURN(error);}
log.cc
bool MYSQL_BIN_LOG::flush_and_sync(bool *synced){ int err=0, fd=log_file.file; if (synced) *synced= 0; mysql_mutex_assert_owner(&LOCK_log); if (flush_io_cache(&log_file)) return 1; uint sync_period= get_sync_period(); if (sync_period && ++sync_counter >= sync_period) { sync_counter= 0; err= mysql_file_sync(fd, MYF(MY_WME));//同步写入文件 if (synced) *synced= 1; } return err;}
mf_locache.c
int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock __attribute__((unused)))if (mysql_file_write(info->file,info->write_buffer,length, info->myflags | MY_NABP))info->error= -1; elseinfo->error= 0;mysql_file.hstatic inline size_tinline_mysql_file_write(#ifdef HAVE_PSI_INTERFACE const char *src_file, uint src_line,#endif File file, const uchar *buffer, size_t count, myf flags){ size_t result;#ifdef HAVE_PSI_INTERFACE struct PSI_file_locker *locker= NULL; PSI_file_locker_state state; if (likely(PSI_server != NULL)) { locker= PSI_server->get_thread_file_descriptor_locker(&state, file, if (likely(locker != NULL)) PSI_server->start_file_wait(locker, count, src_file, src_line); }#endif result= my_write(file, buffer, count, flags);//写入文件#ifdef HAVE_PSI_INTERFACE if (likely(locker != NULL)) { size_t bytes_written; if (flags & (MY_NABP | MY_FNABP)) bytes_written= (result == 0) ? count : 0; else bytes_written= (result != MY_FILE_ERROR) ? result : 0; PSI_server->end_file_wait(locker, bytes_written); }#endif return result;}
my_write.c
size_t my_write(File Filedes, const uchar *Buffer, size_t Count, myf MyFlags){for (;;) {#ifdef _WIN32 writtenbytes= my_win_write(Filedes, Buffer, Count);#else writtenbytes= write(Filedes, Buffer, Count);//调用系统函数#endif}} /* my_write */
errors.c
void wait_for_free_space(const char *filename, int errors){ if (!(errors % MY_WAIT_GIVE_USER_A_MESSAGE)) { my_printf_warning(EE(EE_DISK_FULL), filename,my_errno,MY_WAIT_FOR_USER_TO_FIX_PANIC); my_printf_warning("Retry in %d secs. Message reprinted in %d secs", MY_WAIT_FOR_USER_TO_FIX_PANIC, MY_WAIT_GIVE_USER_A_MESSAGE * MY_WAIT_FOR_USER_TO_FIX_PANIC ); } DBUG_EXECUTE_IF("simulate_no_free_space_error", { (void) sleep(1);//直接退出 return; }); (void) sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);//等待时间}
2.show slave status相关的函数及部分代码
sql_parse.cc
bool dispatch_command(enum enum_server_command command, THD *thd,//转发请求 char* packet, uint packet_length)case COM_QUERY:...mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
sql_parse.cc
void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state)error= mysql_execute_command(thd);sql_parse.cint mysql_execute_command(THD *thd)case SQLCOM_SHOW_SLAVE_STAT://执行 { /* Accept one of two privileges */ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; mysql_mutex_lock(&LOCK_active_mi);//加锁 if (active_mi != NULL) { res = show_master_info(thd, active_mi);//得到信息 } else { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO)); my_ok(thd); } mysql_mutex_unlock(&LOCK_active_mi);//解锁 break; }
slave.cc
bool show_master_info(THD* thd, Master_info* mi) if (mi->host[0]) { DBUG_PRINT("info",("host is set: '%s'", mi->host)); String *packet= &thd->packet; protocol->prepare_for_resend(); /* slave_running can be accessed without run_lock but not other non-volotile members like mi->io_thd, which is guarded by the mutex. */ mysql_mutex_lock(&mi->run_lock); protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin); mysql_mutex_unlock(&mi->run_lock); mysql_mutex_lock(&mi->data_lock);//加锁 mysql_mutex_lock(&mi->rli.data_lock); mysql_mutex_lock(&mi->err_lock); mysql_mutex_lock(&mi->rli.err_lock); ... mysql_mutex_unlock(&mi->rli.err_lock); mysql_mutex_unlock(&mi->err_lock); mysql_mutex_unlock(&mi->rli.data_lock); mysql_mutex_unlock(&mi->data_lock);//解锁 if (my_net_write(&thd->net, (uchar*) thd->packet.ptr(), packet->length())) DBUG_RETURN(TRUE); }
3.show status相关的函数及部分代码
mysqld.cc
static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff){ mysql_mutex_lock(&LOCK_active_mi);//加锁 if (active_mi) { var->type= SHOW_CHAR; var->value= buff; sprintf(buff, "%.3f", active_mi->heartbeat_period); } else var->type= SHOW_UNDEF; mysql_mutex_unlock(&LOCK_active_mi);//解锁 return 0;}
sql_show.cc
static bool show_status_array(THD *thd, const char *wild,SHOW_VAR *variables,enum enum_var_type value_type,truct system_status_var *status_var,onst char *prefix, TABLE *table,bool ucase_names,COND *cond){ for (var=variables; var->type == SHOW_FUNC; var= &tmp) ((mysql_show_var_func)(var->value))(thd, &tmp, buff); //此处调用前面的函数show_heartbeat_period}
sql_show.cc
int fill_status(THD *thd, TABLE_LIST *tables, COND *cond){ if (thd->fill_status_recursion_level++ == 0) mysql_mutex_lock(&LOCK_status);//加锁 if (option_type == OPT_GLOBAL) calc_sum_of_all_status(&tmp); res= show_status_array(thd, wild, (SHOW_VAR *)all_status_vars.buffer, option_type, tmp1, "", tables->table, upper_case_names, cond); if (thd->fill_status_recursion_level-- == 1) mysql_mutex_unlock(&LOCK_status);//解锁 DBUG_RETURN(res);}mysql_mutex_lock(&mi->data_lock);

MySQL 데이터베이스를 업그레이드하는 단계에는 다음이 포함됩니다. 1. 데이터베이스 백업, 2. 현재 MySQL 서비스 중지, 3. 새 버전의 MySQL 설치, 4. 새 버전의 MySQL 서비스 시작, 5. 데이터베이스 복구. 업그레이드 프로세스 중에 호환성 문제가 필요하며 Perconatoolkit과 같은 고급 도구를 테스트 및 최적화에 사용할 수 있습니다.

MySQL 백업 정책에는 논리 백업, 물리적 백업, 증분 백업, 복제 기반 백업 및 클라우드 백업이 포함됩니다. 1. 논리 백업은 MySQLDump를 사용하여 데이터베이스 구조 및 데이터를 내보내며 소규모 데이터베이스 및 버전 마이그레이션에 적합합니다. 2. 물리적 백업은 데이터 파일을 복사하여 빠르고 포괄적이지만 데이터베이스 일관성이 필요합니다. 3. 증분 백업은 이진 로깅을 사용하여 변경 사항을 기록합니다. 이는 큰 데이터베이스에 적합합니다. 4. 복제 기반 백업은 서버에서 백업하여 생산 시스템에 미치는 영향을 줄입니다. 5. AmazonRDS와 같은 클라우드 백업은 자동화 솔루션을 제공하지만 비용과 제어를 고려해야합니다. 정책을 선택할 때 데이터베이스 크기, 가동 중지 시간 허용 오차, 복구 시간 및 복구 지점 목표를 고려해야합니다.

mysqlclusteringenhancesdatabaserobustness andscalabilitydaturedingdataacrossmultiplenodes.itusesthendbenginefordatareplicationandfaulttolerance, highavailability를 보장합니다

MySQL에서 데이터베이스 스키마 설계 최적화는 다음 단계를 통해 성능을 향상시킬 수 있습니다. 1. 인덱스 최적화 : 공통 쿼리 열에서 인덱스 생성, 쿼리의 오버 헤드 균형 및 업데이트 삽입. 2. 표 구조 최적화 : 정규화 또는 정상화를 통한 데이터 중복성을 줄이고 액세스 효율을 향상시킵니다. 3. 데이터 유형 선택 : 스토리지 공간을 줄이기 위해 Varchar 대신 Int와 같은 적절한 데이터 유형을 사용하십시오. 4. 분할 및 하위 테이블 : 대량 데이터 볼륨의 경우 파티션 및 하위 테이블을 사용하여 데이터를 분산시켜 쿼리 및 유지 보수 효율성을 향상시킵니다.

tooptimizemysqlperformance, followthesesteps : 1) 구현 properIndexingToSpeedUpqueries, 2) useExplaintoAnalyzeanDoptimizeQueryPerformance, 3) AdvertServerConfigUrationSettingstingslikeInnodb_buffer_pool_sizeandmax_connections, 4) uspartOflEtOflEtOflestoI

MySQL 기능은 데이터 처리 및 계산에 사용될 수 있습니다. 1. 기본 사용에는 문자열 처리, 날짜 계산 및 수학 연산이 포함됩니다. 2. 고급 사용에는 복잡한 작업을 구현하기 위해 여러 기능을 결합하는 것이 포함됩니다. 3. 성능 최적화를 위해서는 WHERE 절에서 기능 사용 및 GroupBy 및 임시 테이블 사용을 피해야합니다.

MySQL에 데이터 삽입을위한 효율적인 방법은 다음과 같습니다. 1. InsertInto 사용 ... 값 구문 사용 ... 값 구문, 2. 트랜잭션 처리 사용, 3. 트랜잭션 처리 사용, 4. 배치 크기 조정, 5. 인덱스 비활성화, 6. Insertignore 또는 Insert ... ondupliceKeyUpdate를 사용하여 데이터베이스 작동 효율성을 크게 향상시킬 수 있습니다.

MySQL에서는 altertabletable_nameaddcolumnnew_columnvarchar (255) 이후에 필드를 추가하여 altertabletable_namedropcolumncolumn_to_drop을 사용하여 필드를 삭제합니다. 필드를 추가 할 때는 쿼리 성능 및 데이터 구조를 최적화하기위한 위치를 지정해야합니다. 필드를 삭제하기 전에 작업이 돌이킬 수 없는지 확인해야합니다. 온라인 DDL, 백업 데이터, 테스트 환경 및 저하 기간을 사용하여 테이블 구조 수정은 성능 최적화 및 모범 사례입니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

SecList
SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

mPDF
mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.
