第一次操刀数据库分表的教训与经验
2013-11-08 21:50
274 查看
给数据库分表,曾经是个离我很遥远的事情,入行这几年参与过别人主导的分表、分库工作,自己从未操刀,直到我自己的垃圾小站主表10多万记录,相关的其他表30~40万,孱弱的服务器面对谷歌和百度的抓取,导致下载一个页面的时间非常长(PS:谷歌的蜘蛛是我小站的主要用户)。
![](http://images.cnitblog.com/blog/92164/201311/08215247-6c3703752fe84cca9c7905aab24509a0.png)
因为我抓取的主要是stackoverflow、微软社区、雅虎问答等和计算机相关的数据库,存储比较简单,分这么几个表
1:url表,记录每个问题原始的url地址 10万
2:问题内容表,记录问题的主要内容 10万
3:答案表;记录问题的答案 20万
4:用户信息表 20万
5:问题和tag的关系表 30万
我存储的时候比较简单,用问题的title 的哈希值作为唯一值,防止问题重复
以前看过一些文章,关于数据库分表分库的主要是数据的均匀和可扩展性方面的考虑,我考虑常见的几种方式
1:按照时间分表----因为我的采集程序是我想开就开,想关就关,没有时间规律,所以不能这么干
2:按照分类分表----我主要有两个分类1是网站分类,二是tag分类,网站的分类的话stackoverflow的数据占了70%,tag分类的话也不是很均匀,因为我是按照关键词抓取信息的
3:一个障碍,我现在的网站url里面没有分类和时间信息,如果按照分类和时间分表,根据url信息取不到数据了
4:一个侥幸,好在我没把自增id作为url一部分,仅仅是作为优化数据库的标配(记不清在那里看过,有主键的表比没主键的表好,有自增id比没自增id的好)
最后我决定根据我的title的哈希值分表,因为url地址里面包含了这个东西,根据哈希值就可以找到这个表
磨刀霍霍分表,一个表是拆10个表?100个表?1000表?,我是根据哈希值的后三位分表 例如后三位是123 表就是table_123,最后为了防止出现数据不均匀,我一个表拆分1000张,虽然然该集中的还在集中,但是分完表后,一个表要达到10万数据应该是猴年马月的事情了
我的数据库是mysql的,园子里的一个牛人的分表工具很好使
/article/5786174.html 这是地址,最重要的是,这是我在园子里面下载的代码里面唯一有单元测试的代码,用过之后,发现有单元测试的东西质量果然有保证,坚定了我学习单元测试的决心
于是我三下五除二分了8000张表出来,这个时候遇到了郁闷的问题
如何快速有效的吧数据从原来的表里取出来,在放到我新的表里面去,我写了存储过程效果奇差,分一个表要20~40分钟,这在正式生产环境是绝对不允许的,我的代码如下,
因为我去数据的查询语句走不了索引,所以导致我去数据异常缓慢,这算是这次分表的一个教训
教训1:分表时候要考虑取数据和插入数据的性能问题
虽然慢,但是还可以接受,每天晚上弄一个表,1周就把所有的表弄完了
分完表后,我开始改程序,抓取程序和web站点读写数据的部分,我查了一下,
我抓取数据用的orm http://viciproject.com/wiki/projects/mvc/home 彻底不支持分表和分库
我做web站点用的orm https://github.com/toptensoftware/PetaPoco 支持的不是很友好
于是我用园子里面的orm,结果悲剧的一幕开始了,面对一个库8000张表,园子里面4大orm的模型生成工具都不能很好的工作,
教训2:分表前,先要选好orm工具和生成实体类
虽然PetaPoco 不是很友好的支持分表,但是,他简单代码少,很容易就找到了支持分表的方法。
经验3:工具选的越简单越单一,遇到麻烦好处理
于是我开始修改代码,一周后,网站和抓取程序上线,我原以为谷歌抓等待的时间会下降,服务器的cpu和内存和下降,结果悲剧的一幕出现了。
1 监控显示内存急速上升,1G内存就剩下100M了,郁闷的我计划学习lucene,结果还没开工内存就没了
![](http://images.cnitblog.com/blog/92164/201311/08215247-6977e54a52b64c5aa93fedd95d72e307.png)
![](http://images.cnitblog.com/blog/92164/201311/08215248-c1edfb98d216453790e3c2fd5dd5a3d9.png)
2谷歌抓取显示等待时间
![](http://images.cnitblog.com/blog/92164/201311/08215249-bd0557231e9f4fb69fa15bf31cb99be6.png)
到底是什么问题导致了mysql和iis内存上升了( mysql200M、iis300M),悲剧的是我以前没留意mysql和iis分别用多少内存,一时半会不知道2个东西那个出了问题
教训4:服务器性能监控数据很重要,发现问题可以快速定位
到底是那里除了问题?本着我写的程序无bug的态度,必然是mysql的问题,因为分表的sql语句太简单了,mysql处理8张表和8000张表的配置应该不一样吧。。。。。。。
经过乱起八糟的查找,mysql有一个配置
好像是配置打开文件的数量等相关的配置还有一些,可见mysql里面放8000张表和8张表在配置上的确有些区别,因为不是很懂mysql,所以就不研究了,
教训5:分表前要对数据库做基本的随机读写压力测试,测试适合的配置。。。。。。。。。。
应该是我的程序写的有问题
程序有问题改咋整呢,和上次的程序除了分表的sql貌似没啥区别,第一次装vs2012,看看vs2012的内存采样能不能猜出问题
可能因为我是手工点击的,没能模仿谷歌爬虫,vs2012的内存采样没有猜出问题
教训6:性能检测不能过分依赖工具
程序到底是那里有问题呢?
这次比上个版本读取数据库唯一的区别是我直接调用了一个orm不鼓励调用的方法,主要是不这么干,就没法支持分表了
于是我调试了一下,跟进去,虽然没有明显的错误,但是感觉每次new一个对象貌似不靠谱,于是我小改一下,本地测试正常读取数据没问题,让谷歌蜘蛛去做并发测试吧
![](http://images.cnitblog.com/blog/92164/201311/08215249-8b905772f6f542ab9252c06cd230b4d6.png)
上线后,内存就下来了!至于速度有没有提升,需要等几天谷歌抓取统计信息才可以看出来
![](http://images.cnitblog.com/blog/92164/201311/08215250-e825cfa50a764629b3ef2bb7ffdbed33.png)
内存又有了,lucene可以走起了!
![](http://images.cnitblog.com/blog/92164/201311/08215247-6c3703752fe84cca9c7905aab24509a0.png)
因为我抓取的主要是stackoverflow、微软社区、雅虎问答等和计算机相关的数据库,存储比较简单,分这么几个表
1:url表,记录每个问题原始的url地址 10万
2:问题内容表,记录问题的主要内容 10万
3:答案表;记录问题的答案 20万
4:用户信息表 20万
5:问题和tag的关系表 30万
我存储的时候比较简单,用问题的title 的哈希值作为唯一值,防止问题重复
以前看过一些文章,关于数据库分表分库的主要是数据的均匀和可扩展性方面的考虑,我考虑常见的几种方式
1:按照时间分表----因为我的采集程序是我想开就开,想关就关,没有时间规律,所以不能这么干
2:按照分类分表----我主要有两个分类1是网站分类,二是tag分类,网站的分类的话stackoverflow的数据占了70%,tag分类的话也不是很均匀,因为我是按照关键词抓取信息的
3:一个障碍,我现在的网站url里面没有分类和时间信息,如果按照分类和时间分表,根据url信息取不到数据了
4:一个侥幸,好在我没把自增id作为url一部分,仅仅是作为优化数据库的标配(记不清在那里看过,有主键的表比没主键的表好,有自增id比没自增id的好)
最后我决定根据我的title的哈希值分表,因为url地址里面包含了这个东西,根据哈希值就可以找到这个表
磨刀霍霍分表,一个表是拆10个表?100个表?1000表?,我是根据哈希值的后三位分表 例如后三位是123 表就是table_123,最后为了防止出现数据不均匀,我一个表拆分1000张,虽然然该集中的还在集中,但是分完表后,一个表要达到10万数据应该是猴年马月的事情了
我的数据库是mysql的,园子里的一个牛人的分表工具很好使
/article/5786174.html 这是地址,最重要的是,这是我在园子里面下载的代码里面唯一有单元测试的代码,用过之后,发现有单元测试的东西质量果然有保证,坚定了我学习单元测试的决心
于是我三下五除二分了8000张表出来,这个时候遇到了郁闷的问题
如何快速有效的吧数据从原来的表里取出来,在放到我新的表里面去,我写了存储过程效果奇差,分一个表要20~40分钟,这在正式生产环境是绝对不允许的,我的代码如下,
DELIMITER $$ USE `learn`$$ DROP PROCEDURE IF EXISTS `genQu`$$ CREATE DEFINER=`root`@`localhost` PROCEDURE `genQu`() BEGIN DECLARE i INT DEFAULT 0; DECLARE l_sql VARCHAR(4000); WHILE i <1000 DO SET l_sql=CONCAT("INSERT INTO question_",i," SELECT * FROM question WHERE RIGHT(question.titlecode,3)=",i); SET @SQL=l_sql; SELECT @SQL; PREPARE s1 FROM @SQL; EXECUTE s1; DEALLOCATE PREPARE s1; SET i = i + 1; END WHILE; END$$ DELIMITER ;
因为我去数据的查询语句走不了索引,所以导致我去数据异常缓慢,这算是这次分表的一个教训
教训1:分表时候要考虑取数据和插入数据的性能问题
虽然慢,但是还可以接受,每天晚上弄一个表,1周就把所有的表弄完了
分完表后,我开始改程序,抓取程序和web站点读写数据的部分,我查了一下,
我抓取数据用的orm http://viciproject.com/wiki/projects/mvc/home 彻底不支持分表和分库
我做web站点用的orm https://github.com/toptensoftware/PetaPoco 支持的不是很友好
于是我用园子里面的orm,结果悲剧的一幕开始了,面对一个库8000张表,园子里面4大orm的模型生成工具都不能很好的工作,
教训2:分表前,先要选好orm工具和生成实体类
虽然PetaPoco 不是很友好的支持分表,但是,他简单代码少,很容易就找到了支持分表的方法。
经验3:工具选的越简单越单一,遇到麻烦好处理
于是我开始修改代码,一周后,网站和抓取程序上线,我原以为谷歌抓等待的时间会下降,服务器的cpu和内存和下降,结果悲剧的一幕出现了。
1 监控显示内存急速上升,1G内存就剩下100M了,郁闷的我计划学习lucene,结果还没开工内存就没了
![](http://images.cnitblog.com/blog/92164/201311/08215247-6977e54a52b64c5aa93fedd95d72e307.png)
![](http://images.cnitblog.com/blog/92164/201311/08215248-c1edfb98d216453790e3c2fd5dd5a3d9.png)
2谷歌抓取显示等待时间
![](http://images.cnitblog.com/blog/92164/201311/08215249-bd0557231e9f4fb69fa15bf31cb99be6.png)
到底是什么问题导致了mysql和iis内存上升了( mysql200M、iis300M),悲剧的是我以前没留意mysql和iis分别用多少内存,一时半会不知道2个东西那个出了问题
教训4:服务器性能监控数据很重要,发现问题可以快速定位
到底是那里除了问题?本着我写的程序无bug的态度,必然是mysql的问题,因为分表的sql语句太简单了,mysql处理8张表和8000张表的配置应该不一样吧。。。。。。。
经过乱起八糟的查找,mysql有一个配置
SHOW GLOBAL STATUS LIKE 'open%tables%'
好像是配置打开文件的数量等相关的配置还有一些,可见mysql里面放8000张表和8张表在配置上的确有些区别,因为不是很懂mysql,所以就不研究了,
教训5:分表前要对数据库做基本的随机读写压力测试,测试适合的配置。。。。。。。。。。
应该是我的程序写的有问题
程序有问题改咋整呢,和上次的程序除了分表的sql貌似没啥区别,第一次装vs2012,看看vs2012的内存采样能不能猜出问题
可能因为我是手工点击的,没能模仿谷歌爬虫,vs2012的内存采样没有猜出问题
教训6:性能检测不能过分依赖工具
程序到底是那里有问题呢?
这次比上个版本读取数据库唯一的区别是我直接调用了一个orm不鼓励调用的方法,主要是不这么干,就没法支持分表了
learnDAL.learnDB.GetInstance()
public static IFactory Factory { get; set; } public static learnDB GetInstance() { if (_instance != null) return _instance; if (Factory != null) return Factory.GetInstance(); else { //备注以前是 return new learnDB() _instance = new learnDB(); return _instance; } }
于是我调试了一下,跟进去,虽然没有明显的错误,但是感觉每次new一个对象貌似不靠谱,于是我小改一下,本地测试正常读取数据没问题,让谷歌蜘蛛去做并发测试吧
![](http://images.cnitblog.com/blog/92164/201311/08215249-8b905772f6f542ab9252c06cd230b4d6.png)
上线后,内存就下来了!至于速度有没有提升,需要等几天谷歌抓取统计信息才可以看出来
![](http://images.cnitblog.com/blog/92164/201311/08215250-e825cfa50a764629b3ef2bb7ffdbed33.png)
内存又有了,lucene可以走起了!
相关文章推荐
- 第一次操刀数据库分表的教训与经验--白干一场
- 第一次做贴片封装的PCB,自己的一些经验教训
- 第一次开发分享的经验教训
- 第一次实施Oracle Text项目,经验与教训记录
- 第一次开发分享的经验教训
- 经验:搞代码就行了,别乱动数据库(【测试数据要尽量写好一点,只改不删,后期不要轻易删表记录】。关联复杂。oracle报错难以解决)==教训经历如下:
- 数据库维护的经验教训 推荐
- 即将毕业的我第一次出来找实习的经历和教训 ——一个普二计算机专业程序员的碰壁经验分享
- 第一次安装DB2的经验教训
- 数据库设计中的一些小经验,拿来分享一下(有血的教训)。
- Excel数据表导入数据库的经验与教训
- 软件测试经验与教训一
- 数据库设计经验浅谈
- 一个项目的经验教训:关于打乱和拆分数据
- 我的编码经验教训总结
- c++模块间传递参数的一些经验教训
- 实践出真知 有关数据库设计经验简介
- 数据库设计经验谈
- Mybatis为什么第一次访问数据库会慢?
- (十)2005年我的第一次软件行业创业,烧掉30万、2年时间打水漂的惨痛教训总结篇