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

[经验分享] memcached罢工引发的血案-博客园评论超时问题处理过程

[复制链接]

尚未签到

发表于 2015-8-31 11:26:21 | 显示全部楼层 |阅读模式
  起因
  话说2009年12月4日的下午,博客园团队的一位在数据库服务器中修改了一个设置:
  
DSC0000.png
  将"Use query governor to prevent long-running queries"设置为500,500代表的是查询成本,不是查询执行时间,如果SQL Server认为查询成本超过500,就会返回超时错误。
  之前我们经常使用这个设置,这样可以避免一些执行时间过长的查询影响整体数据库的性能。但这不是解决问题的办法,只是让局部问题不去影响整体,真正解决问题还是要优化执行时间长的查询。
  而就在修改过这个设置之后某个时候,担任缓冲重任的memcached服务突然偷偷地罢工了,血案就这样开始了...
  发现问题
  有些用户在博客中发评论时出现了超时错误,有人在闪存上进行反映,我们在闪存看到并进行测试,也遇到了超时问题,当时我们以为是同时连接过多造成服务器压力大造成的,从日志中发现有过于频繁访问的IP,屏蔽了该IP之后,可以正常发表评论了,我们以为问题已经解决了,从最新评论看,大家也能发表评论。
  实际上问题依然存在,会在特定的条件下发生,只不过我们的测试时没有遇到这样的条件。如果没有设置"Use query governor to prevent long-running queries",这个问题更难发现,因为这时发评论只会速度变慢,不会出现超时,大家不会去反馈这个速度慢的问题。后来,超时出现越来越频繁,有用户在闪存上进行反馈,我们才知道了这个问题。
  采取措施
  我们怎么也没想到memcached服务已经罢工了,之前memcached服务还从来没罢工过,于是把解决问题的焦点放在评论功能相关的数据库优化。在SQL Server 2005管理工具中执行添加评论的存储过程,执行速度也很慢,查看执行计划,发现成本在聚集索引的插入上,于是我们以为是评论表的聚集索引设置有问题(看来不能仅从执行计划去分析问题)。评论表的聚集索引本来是建立在自增ID上的(博客文章表的聚集索引建立在发表时间上),因为评论表的查询主要就是根据ParentID进行查询(查询结果根据ID进行排序),之外最多的操作就是插入记录。既然成本在聚集索引的插入上,我们就取消了聚集索引,这样可以避免在插入记录时的聚集索引插入。这样操作之后,发评论的速度提升了,但速度还是不理想,还是会出现超时...
  柳暗花明
  后来,无意间发现memcached服务停掉了,立即想到这才是罪魁祸首,不是聚集索引的问题,为什么会这么想呢,看一下添加评论的存储过程就知道了:




BEGIN TRANSACTION
UPDATE blog_Content
SET FeedBackCount = FeedBackCount+1,LastCommentTime = GETDATE()
WHERE [ID] = @ParentID
INSERT INTO blog_Comment([Text],Author)VALUES(@Text,@Author)   
Select @ID = @@Identity   
COMMIT TRANSACTION
  之前发表评论的性能就不怎么理想,瓶颈就在对blog_Content表FeedBackCount字段的更新上,因为blog_Content是查询最频繁的表,我们几乎对所有查询都使用了WITH(NOLOCK),但是发表评论的性能还是存在问题。memcached服务罢工,直接的结果就是对blog_Content的查询大量增加,在发表评论时的Update操作成本就很高,从而造成超时。
  启动memcached服务,问题立即解决。
  解决问题
  但是问题并没有真正解决,真正的问题是在添加评论时对blog_Content表FeedBackCount字段的更新。
  针对这个问题,我采用一种解决方法:在插入评论时不进行Update操作,而是将评论所属的文章ID插入另外一张表中,表结构如下:




CREATE TABLE [dbo].[blog_Comment_CountLog](
    [EntryID] [int] NOT NULL,
    [FeedbackCount] [int] NOT NULL
)
  插入评论时,进行下面的操作:  




INSERT INTO blog_Comment_CountLog(EntryID,FeedbackCount)VALUES(@ParentID,1)
  显然,这个插入操作速度很快。
  删除评论时,进行下面的操作:




INSERT INTO blog_Comment_CountLog(EntryID,FeedbackCount)VALUES(@ParentID,-1)
  那么怎么更新文章的评论数呢?
  然后通过SQL Server的任务计划定时执行存储过程进行更新:




SET XACT_ABORT ON
BEGIN TRANSACTION
UPDATE [blog_Content]
SET [FeedBackCount] = [FeedBackCount]+CommentCount
FROM [CNBlogs].[dbo].[blog_Content] A
INNER JOIN
(SELECT EntryID,SUM(FeedbackCount) AS CommentCount FROM blog_Comment_CountLog GROUP BY EntryID ) AS B
ON A.ID=B.EntryID
DELETE blog_Comment_CountLog
COMMIT TRANSACTION
  这样还会带来批量更新的好处,在这个任务计划的间隔时间内添加评论,如果属于同一篇文章,只要执行一次更新操作。
  采用这个方法后,发表评论的性能有了明显提升,现在大家发评论可以看到评论提交的执行时间。
  小结
    在处理问题时,不要着急,要全面分析,把可能引起问题的因素尽量多地考虑到,在动手解决问题之前,多花些时间考虑从何处下手。
  在开发中,异步是一个提高性能的有效方法。
  在我们解决各种问题的过程中,从网上获得了很多启发,如果有人遇到过类似问题并分享了自己的处理经验,会节省我们很多时间。
  大家遇到问题时多数会先Google一下吧,如果大家都只想着Google一下,而不去分享,这个生态链就很难维系。别人的分享帮助了你,你的分享帮助了别人,在这种互相帮助中,大家都会进步。
  在刚解决一个问题的时候,是分享的最佳时期,如果此时不分享,也许就永远不会分享,分享的不仅是解决问题的方法,更是解决问题时的那种兴奋。这种兴奋是程序人生的乐趣所在!

运维网声明 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-106754-1-1.html 上篇帖子: 云计算之路-柳暗花明:为什么memcached会堵车 下篇帖子: 小白谈memcache和memcached的区别
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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