设为首页 收藏本站
查看: 709|回复: 0

[经验分享] 由mysql timestamp字段引发的一个系统bug

[复制链接]

尚未签到

发表于 2015-12-21 09:35:27 | 显示全部楼层 |阅读模式
2015-06-30 13:11:00左右,memcache由于硬件故障,莫名重启,导致数据库访问量突然增大(按照之前的测试结果,远未到达系统瓶颈),且当时syscpu 远高于正常值。
监控信息如下:
DSC0000.png

当时的mysqld堆栈信息如下:



  • Thread 50 (Thread 0x2afb6591a700 (LWP 7020)):

  • #0 0x0000003c34ef808f in __lll_unlock_wake_private () from /lib64/libc.so.6
  • #1 0x0000003c34e9dccc in _L_unlock_2226 () from /lib64/libc.so.6
  • #2 0x0000003c34e9db01 in __tz_convert () from /lib64/libc.so.6
  • #3 0x0000000000783012 in Time_zone_system::gmt_sec_to_TIME(st_mysql_time*, long) const ()
  • #4 0x00000000007c177b in Field_timestampf::get_date_internal(st_mysql_time*) ()
  • #5 0x00000000007c23dd in Field_temporal_with_date::val_str(String*, String*) ()
  • #6 0x0000000000672fa8 in Protocol_text::store(Field*) ()
  • #7 0x00000000006722f5 in Protocol::send_result_set_row(List<Item>*) ()
  • #8 0x00000000006c77af in select_send::send_data(List<Item>&) ()
  • #9 0x00000000006db6b0 in end_send(JOIN*, st_join_table*, bool) ()
  • #10 0x00000000006d6c4f in evaluate_join_record(JOIN*, st_join_table*) ()
  • #11 0x00000000006d6fbb in sub_select(JOIN*, st_join_table*, bool) ()
  • #12 0x00000000006d61e8 in JOIN::exec() ()
  • #13 0x000000000071f0d5 in mysql_select(THD*, TABLE_LIST*, unsigned int, List<Item>&, Item*, SQL_I_List<st_order>*, SQL_I_List<st_order>*, Item*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) ()
  • #14 0x000000000071f935 in handle_select(THD*, select_result*, unsigned long) ()
  • #15 0x000000000057fe02 in execute_sqlcom_select(THD*, TABLE_LIST*) ()
  • #16 0x00000000006f935c in mysql_execute_command(THD*) ()
  • #17 0x00000000006fe5e8 in mysql_parse(THD*, char*, unsigned int, Parser_state*) ()
  • #18 0x00000000006ffdc9 in dispatch_command(enum_server_command, THD*, char*, unsigned int) ()
  • #19 0x0000000000789a08 in threadpool_process_request(THD*) ()
  • #20 0x000000000078a9dd in worker_main(void*) ()
  • #21 0x0000000000b4a8c3 in pfs_spawn_thread ()
  • #22 0x0000003c352079d1 in start_thread () from /lib64/libpthread.so.0
  • #23 0x0000003c34ee88fd in clone () from /lib64/libc.so.6
从堆栈可以看到大部分请求都在调用glibc的时区转换函数,但该函数由于全局锁的原因,在并发环境下产生了热点竞争。

深入分析mysql时区相关的函数:



  • void

  • Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
  • {
  •   struct tm tmp_tm;
  •   time_t tmp_t= (time_t)t;

  •   localtime_r(&tmp_t, &tmp_tm);
  •   localtime_to_TIME(tmp, &tmp_tm);
  •   tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
  •   adjust_leap_second(tmp);
  • }

继续进入localtime_r函数


  • struct tm *

  • __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
  • {
  •   long int leap_correction;
  •   int leap_extra_secs;

  •   if (timer == NULL)
  •     {
  •       __set_errno (EINVAL);
  •       return NULL;
  •     }

  • __libc_lock_lock (tzset_lock);

  •   /* Update internal database according to current TZ setting.
  •      POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
  •      This is a good idea since this allows at least a bit more parallelism. */
  •   tzset_internal (tp == &_tmbuf && use_localtime, 1);

  •   if (__use_tzfile)
  •     __tzfile_compute (*timer, use_localtime, &leap_correction,
  •               &leap_extra_secs, tp);
  •   else
  •     {
  •       if (! __offtime (timer, 0, tp))
  •     tp = NULL;
  •       else
  •     __tz_compute (*timer, tp, use_localtime);
  •       leap_correction = 0L;
  •       leap_extra_secs = 0;
  •     }

  •   if (tp)
  •     {
  •       if (! use_localtime)
  •     {
  •       tp->tm_isdst = 0;
  •       tp->tm_zone = "GMT";
  •       tp->tm_gmtoff = 0L;
  •     }

  •       if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
  •         tp->tm_sec += leap_extra_secs;
  •       else
  •     tp = NULL;
  •     }

  •   __libc_lock_unlock (tzset_lock);

  •   return tp;
  • }

很清楚的看到,在调用系统时区转换时,有全局锁__libc_lock_lock的保护,导致线程并发环境下,系统性能受限。

而在time_zone=system时,会调用该函数从而获取系统的时区。如果将time_zone='+8:00'则不会调用系统时区.
对此,真实的模拟了线上的case(分别对time_zone=system和time_zone='+8:00'做了压测):




  • mysqlslap --no-defaults -u$user -p$password --create-schema=DianPingTS -h$host -P$port --number-of-queries=1000000000 --concurrency=30 --query="select AddTime,UpdateTime from $table where addtime>='2015-07-01 15:21:35' and addtime<='2015-07-01 17:33:35';"
以下是测试结果:
DSC0001.png

由此可见,在time_zone='+8:00'在timestamp类型的大量转换情况下,性能能得到质的提升..


小伙伴们,如果也遇到该问题,只要将time_zone='+8:00' (注意地区在东8区哦)就可以了..^_^

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-154100-1-1.html 上篇帖子: MySQL配置文件my.cnf优化详解 下篇帖子: 项目实际用到的一些mysql优化(记录)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表