大数据引发的小悲剧(二)
和上一次的现象差不多:数据量小时一切正常,稍微大一点monitord就会没响应。
具体跟踪之,发现如下现象:
(1)MonitorServer给monitord发送请求,一切都正常;但是没有收到monitord返回的响应;
(2)monitord收到并解析请求,一切正常;
(3)monitord执行请求,一切正常;
(4)最后一步:monitord更新配置文件,超时。
崩溃。。。
写文件居然会超时?这得多大的数据量阿,俺们的数据量也没达到这么恐怖的底部呀?
废话少说,扒开代码一看,彻底拜服:
1 static int set_threshold_cfg() 2 { 3 ... 4 5 int i=0; 6 for(;i<num; i++) 7 { 8 ConfigSetKey(); 9 } 10 ... 11 } 12 13 int ConfigSetKey(void *CFG_file, void *section, void *key, void *buf) 14 { 15 FILE *fp1, *fp2; 16 char buf1[MAX_CFG_BUF + 1]; 17 int line_no, line_no1, n, ret, ret2; 18 char *tmpfname; 19 20 ret = ConfigGetKey(CFG_file, section, key, buf1); 21 if(ret <= CFG_ERR && ret != CFG_ERR_OPEN_FILE) return ret; 22 if(ret == CFG_ERR_OPEN_FILE || ret == CFG_SECTION_NOT_FOUND) 23 { 24 25 if((fp1 = fopen((char *)CFG_file, "a")) == NULL) 26 27 return CFG_ERR_CREATE_FILE; 28 29 if(fprintf(fp1, "%c%s%c\n", CFG_ssl, section, CFG_ssr) == EOF) 30 { 31 fclose(fp1); 32 return CFG_ERR_WRITE_FILE; 33 } 34 if(fprintf(fp1, "%s=%s\n", key, buf) == EOF) 35 { 36 fclose(fp1); 37 return CFG_ERR_WRITE_FILE; 38 } 39 fclose(fp1); 40 return CFG_OK; 41 } 42 if((tmpfname = tmpnam(NULL)) == NULL) 43 { 44 return CFG_ERR_CREATE_FILE; 45 } 46 if((fp2 = fopen(tmpfname, "w")) == NULL) 47 return CFG_ERR_CREATE_FILE; 48 ret2 = CFG_ERR_OPEN_FILE; 49 50 if((fp1 = fopen((char *)CFG_file, "rb")) == NULL) goto w_cfg_end; 51 52 if(ret == CFG_KEY_NOT_FOUND) 53 line_no1 = CFG_section_line_no; 54 else /* ret = CFG_OK */ 55 line_no1 = CFG_key_line_no - 1; 56 for(line_no = 0; line_no < line_no1; line_no++) 57 { 58 ret2 = CFG_ERR_READ_FILE; 59 n = FileGetLine(fp1, buf1, MAX_CFG_BUF); 60 if(n < 0) goto w_cfg_end; 61 ret2 = CFG_ERR_WRITE_FILE; 62 if(fprintf(fp2, "%s\n", buf1) == EOF) goto w_cfg_end; 63 } 64 if(ret != CFG_KEY_NOT_FOUND) 65 for( ; line_no < line_no1+CFG_key_lines; line_no++) 66 { 67 ret2 = CFG_ERR_READ_FILE; 68 n = FileGetLine(fp1, buf1, MAX_CFG_BUF); 69 if(n < 0) goto w_cfg_end; 70 } 71 ret2 = CFG_ERR_WRITE_FILE; 72 if(fprintf(fp2, "%s=%s\n", key, buf) == EOF) goto w_cfg_end; 73 while(1) 74 { 75 ret2 = CFG_ERR_READ_FILE; 76 n = FileGetLine(fp1, buf1, MAX_CFG_BUF); 77 if(n < -1) goto w_cfg_end; 78 if(n < 0) break; 79 ret2 = CFG_ERR_WRITE_FILE; 80 if(fprintf(fp2, "%s\n", buf1) == EOF) goto w_cfg_end; 81 } 82 ret2 = CFG_OK; 83 w_cfg_end: 84 if(fp1 != NULL) fclose(fp1); 85 if(fp2 != NULL) fclose(fp2); 86 if(ret2 == CFG_OK) 87 { 88 ret = FileCopy(tmpfname, CFG_file); 89 if(ret != 0) return CFG_ERR_CREATE_FILE; 90 } 91 remove(tmpfname); 92 return ret2; 93 }
每写入一项配置就执行一次“打开/关闭文件”操作,算下来每个请求大概要执行几万次打开/关闭文件操作,超时也就不奇怪了。
找到问题根源,就很好解决了:将写配置文件函数重写,只执行一次打开/关闭文件操作。具体过程略。