典型bug分析

一.能问题

1.sql语句慢的问题

实例1:超级宝贝的投票日志记录表

【原因分析】:

  从业务上讲,投票日志详细表是当用户需要查看某个投票日志的详细记录时会使用到。即查询这个表时会使用到voteid作为过滤条件,而表只有votelogid的主键索引,此查询将使用全表扫描。

【解决方案】:

  为superbaby2011_votelog表添加一条索引

Create index idx_superbaby2011_votelog_voteid  on superbaby2011_votelog(voteid);

实例2:车型库点评库

http://price.pcauto.com.cn/comment/sg3188/m15081/

车型库点评1.0车型点评终端页,对每个车型进行综合评分和排名。

【现象】:页面响应时间长,对语句进行“解释计划”cost值为1.2万以上。

【分析语句】:

1、查询语句较复杂,层次多。

21个车系下有10-200多个车型,每个车型下有多个评论,需要统计分

的记录多。

3、直接在数据库中进行统计排名。

【解决方案】:

减少查询层次,从数据库中查出相关信息再在程序中进行计算处理

实例3:美搭2.0首页

http://m.pclady.com.cn 排行榜类型

美搭2.0首页,各分类有一块最近有分享的用户列表(取最近5个)

【现象】:

当分享的用户很多、单个用户也分享较多配饰时,页面打开速度很慢。

【原因分析】:

红框部分,对应的查询语句

由于goods表有40W左右的记录,语句的执行计划分析,可以看出此语句已经用了索引,但执行还是较慢,已经没办法通过建索引来解决这个问题。

【解决方案】:

由于只是一个页面用到,加缓存可以有效减少查询次数增加时间条件,即取最近7天内有发布的数据的用户(从业务上讲,如果最近7天没用户发表,可能会出现结果为空,可适当调整时间长度)

实例4:女性网腕表库

语句在查询时不使用索引基于-objId字段的索引

【原因分析】:

  表中的objIdvarchar类型。mysql会自动将字符型用to_number()函数进行转换,从而导致不使用此索引。  

【解决方案】:

  将SQL语句改为select id from XXX where objId=111and objType='product';或者把表中的objId数据类型改成int型。

2.查询语句多的问题

实例1: 母婴用品库

【现象】:

分类产品列表页面 ,每访问一个页面有执行SQL 1000多次。

【原因分析】:

产品索引页面,分筛选条件进行统计,进分析发现,每个条件或分类都是单条SQL语句去查询的。例如:时间轴,分了9类,在查询的时候用于9SQL去查询,一个ID一个ID的查出来

【解决方案】:

1、是否可以批量查询

  即使用group by 方式将所有时间轴的数量一次统计出来,然后再处理显示。

select XX,count(*) from table group by typeid;

2、是否可以精简业务

  同上功能,是否可以考虑不显示统计信息。

3、是否按需加载


   更多品牌,这块点的人较少,改为按需加载可以很大程度上减少查询量。

实例2:评论系统

【现象】:

查询后台的一些系统配置里面的状态设置,一段时间内总查询次数18056次,这个配置项查询都要查11498次。

【原因分析】:

配置项,可在管理后台配置主要是方便修改,但配置项的值一般情况下设置好后,不会修改;查询次数

多是因为每次读评论时都需要查询这个配置项。

【解决方案】:

把此配置项相关信息存放在内存中,当应用启动时查询数据库将配置加载到内存中,当有修改或更新时,更新内存中的值;查询评论时直接从内存中读取此参数的值,不再查询数据库。

实例3:汽车论坛

【现象】:

查询结果已经加上了MC缓存,但是再次访问还是会继续查询数据库,版块页的以下语句:

SELECT * FROM table WHERE fid = 0

SELECT * FROM table WHERE blockId = 0

SELECT * FROM table WHERE pid = 0

【问题分析】:

这些无效sql查询结果是空的,导致MC无法缓存这部分数据从而引起数据库查询次数过多。

【解决方案】:

对这种无效数据加上异常判断,不查询这种异常数据。

实例4:车型库点

【现象】:

  点评投票操作更新数据库较频繁导致数据库负载高。

【解决方案】:

     这种情况可以考虑批量更新数据库减少数据库负载。

实例5:数据库更新语句多

【现象】:

  如有访问计数器之类的,访问一次写一次数据库,这样会过多的访问数据库。


【解决方案】:

  将计数值先放内存或MC中,批量写入数据库,常用方法按量和按时写入。

实例6:女性网婉表库

【现象】:应用上线后不久,数据库负载很高,但应用的数据量和访问量都不高。

【问题分析】:

1、从应用访问的accesslog中分析得出,访问大多来自爬虫,主要集中在访问索引页;很多查询实际上并没有结果。

2、索引页分析,查询筛选条件太多,缓存命中率很低,基本每次查询都需要查数据库。


【解决方案】:

1、判断爬虫的访问,如果爬虫访问到的页面是没有结果的,直接返回404状态;这样爬虫短时间内就不会再来访问。

2、将没有结果的筛选条件直接隐藏链接,不可点击。效果如电脑和汽车产品库的索引页。

3、使用xindex索引架构。

3.缓存使用不当引起的问题

实例1:汽车wap版车型库参数配置页

【现象】:

车型配置页MC读写请求数差不多300次。

【原因分析】:

车型配置页参数对象缓存数较多,导致页面MC请求数多。

【解决方案】:

车型配置页参数变化比较少,把对象缓存改成页面缓存。

实例2:游戏赛事竞猜系统列表页

【现象】:

竞猜系统列表页MC读写请求数差不多200次。

【原因分析】:

列表页的每个竞猜作为一个对象缓存,然后一个个的从MC查,导致页面MC请求数多。

【解决方案】:

列表页竞猜信息变更比较频繁,改成页面缓存不适合。可以把页面的竞猜对象缓存批量从MC查询出来,减少请求数。

实例3:美搭1.0

【现象】:

使用MC后比不使用访问速度更慢。

【原因分析】:

      列表页,设计为下拉刷新加载多4条搭配信息,单页显示最多100个,然后进行分页,在修改前是将单页的所有数据都取出来存都放在MC中了,导致响应时间较长。

【解决方案】:

下拉加载4条的页面,改成刚开始只查询前四条记录并存放到MC,其他待加载时再查询数据库并存放到MC中,缓存未过期时,直接从MC中取结果。

实例4:车型点评库

【现象】:

经销商终端页内存使用多

【原因分析】:

 这个页面的MC对象较多(每个对象都占用一定的内存空间),导致内存使用多。

【解决方案】:

由于没有办法从MC对象数量层面上优化,而省份、账号、车系、车型这些对象较多且使用频率高,开启一级缓存能少内存的使用。

注意:一级缓存一般默认不启用一级缓存,比较适合MC对象多并且使用频率高的项目。

实例5:母婴用品库

【现象】:

   缓存颗粒过大不利于部分信息的更新

【解决方案】:

产品列表页中显示了N个产品的相关信息,其中部分信息为基本上不变的(标题、价格、产品图片),部分为常变的(综合评分、点评数),在这里如果将缓存块的values设置为所有信息内容,要保证信息即时更新就得整个缓存块内容进行更新,如果分开缓存,就可以对不同的缓存块设置不同的cache时间,同时对于变化较小的数据,缓存时间可以设置长一些。

4.memcache使用问题

实例1: 女性网美搭

【现象】:

  访问美搭搜索时,经常报错。

【原因分析】:

  因为是以关键字为memcached key,当输入的关键字太长时,引起key太长。

【解决方案】:

  限制memcachekey长度。

实例2:化妆品库

【现象】:

  访问产品终端页应用LOG中报错。

【原因分析】:

  Memcachedkey名称不支持中文。

【解决方案】:

 将key名改为字符串+产品ID的方式。

5.网络流量大问题

实例1:汽车报价

汽车报价首页、索引页,页面有个左树,左树将各品牌的车按品牌、厂商、车系进行统计,形成一个树形结构,树形结果中包含所有报价库中的车系。

【现象】:

  左树修改后,页面流量增加较多(在打开gzip的情况下还是很大流量),单个页面没开gzip的情况下流量超500K

gzip后仍有60K以上。

【原因分析】:

1、左树在设计时采用的是默认将所有车厂、车系都用JS生成了,在用户访问时一次性加载。

2、从业务上讲,用户可能会关注某个品牌的车,大多数品牌用户并不会去关注,加载所有车系有些浪费带宽。

3、一次性加载改为按需加载,对用户的影响并不大,用户点击后在1秒以内完全能加载完成,用户感觉不到慢。

【解决方案】:

默认只加载品牌这一级,车厂、车系点击后才加载。

6.mysql分表太多的问题

实例1bip应用数据库分表

【现象】:

bipmysql库无法打开查看表信息。

【原因分析】:

bip最初设计是准备2W张表,由于打开文件数的限制,打开这么多文件,mysql 就不能再处理请求了。

【解决方案】:

分析线上已有数据量情况,再加上预计增长的量,最终把表减少到2000张。

7.业务相关-同步机制

实例1:竞猜系统

【现象】:

竞猜系统规定一个用户每天只可以领取免费筹码一次,并发领取筹码时发现相同用户重复领取问题

【原因分析】:

出现重复领取是因为开始没有加线程加锁,在多并发时容易出现重复领取的情况。

【解决方案】:

在相应动作上加了同步机制,防止了重复的情况出现。

8.SSI相关

【现象】:

应用负载不高,响应低,nginx返回超时。

【原因分析】:

可能是因为SSI设置超时时长大于等于nginx设置超时的时间了。

【解决方案】:

SSI超时时间设置小一点,否则可能会影响其他内容访问。

9.有性能问题驱动版本

实例1: 女性网美搭

【现象】:

   应用更新新版本后,出现了较多的重启现象,通过分析定位在后台操作时会出现。

【原因分析】:

 查看Resinlog,没有发现OutOfMemoryError ,在resin的根目录下,发现有错误日志文件 hs_err_pid20194.log

 出现这种情况一般是JVM crash 了,多数情况下是触发了jvm编译器的bUG引起,将JDK进行升级可解决

【解决方案】:

 在测试环境进行JDK版本更换相关测试,测试后如无问题,再在保证不对用户产生大影响的前提下,更新生产环境其中一台应用的JDK版本为新版本,进行观察。确认问题不再出现,再更新别的机器。

实例2:汽车报价

【现象】:

汽车报价有很100多条线程挂起堵塞,时间越久挂起的线程就越多,并且每个挂起的线程都有报错:

【原因分析】:

MC客户端2.5以后的版本引用了java nio ,而java nio 不支持soTimeout(该方法是用来设置读取堵塞超时) 。也就是说如果有线程读取

MC数据,而MC服务器没有响应的话这些线程就会堵塞挂起。

【解决方案】:

MC客户端升级到2.6.5以上版本,这个版本已经修复了这个bug