如何打造一个日均PV千万级别的大型系统?
《如何打造一个日均PV千万级别的大型系统?》要点: 作者介绍 周金桥,具有丰富的系统规划、设计、开发、运维及团队组织管理工作经验,熟悉.Net、J2EE技术架构及应用.微软2008-2012五届最有价值专家(MVP),2009年单独著有《ASP.NET夜话》一书,2010年与人合著《程序员的成长之路》.至今活跃在多个技术社区. 本文我选定的方向是如何开发一个大型系统,在这里我对大型系统的定义为日均PV在千万级以上,而京东和淘宝这类则属于巨型系统了.因此在本篇中讲述的都是基于一些开源免费的技术实现,至于通过F5硬件加速、DNS来实现负载均衡、CDN加速等需要花钱购买的技术或者服务则不再本篇介绍范围之类. 一、从两个系统说起1、某移动互联网公司服务器端架构图上图是某移动互联网公司的服务器端架构图,它支撑了国内外数百万客户端的访问请求,有如下特点:
2、某公司生产管理系统架构图上图是为某公司的一个分散型系统做的架构设计,这家公司拥有多个跨市、跨省的生产片区,在各片区都有自己的生态车间,各片区与总公司之间通过数据链路连接.这个系统的特点是所有的流水线上的产品都贴有唯一的条码,在生产线的某个操作位操作之前都会扫描贴在产品上的条码,系统会根据条码做一些检查工作,如:产品条码是否应被使用过(比如之前应发货给客户过)、产品是否完成了本道工序之前的全部必须完成工序,如果满足条件则记录当前操作工序名称、操作人、操作时间和操作结果等. 一件产品从上线到完成有数十道工序,而每月下线的产品有少则数十万、多则数百万,一个月下来的数据量也是不小的.特别是在跨厂区网络不稳定的情况下如何保证对生产的影响最小. 本系统架构特点:
由于总部其它地方生产规模较小,所以生产分布未采用复杂架构,不过因为从客户处退回的不良产品都会在总部生产车间进行返修处理,因此总部生产系统需要保存分部生产车间数据,因此分部生产车间数据会同时写进分部生产数据库和分部MQ服务器,然后由总部ETL服务器读取写入到总部系统中.在分部与总部网络中断的情况下分部系统仍可独立工作,直到网络恢复. 二、系统质量保证1、单元测试单元测试是指对软件中的最小可测试单元进行检查和验证.通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为,常见的开发语言都有对应的单元测试框架,常见的单元测试工具:Junit/Nunit/xUnit.Net/Microsoft.VisualStudio.TestTool 关于单元测试的重要性和如何编写单元测试用例,在本篇就不详述了,网上有大量相关的文章.总之,越大型的系统、越重要的系统,单元测试的重要性越大. 针对一些需要外部依赖的单元测试,比如需要Web容器等,可以使用mock测试,Java测试人员可以使用EasyMock这个测试框架,其网址是http://easymock.org/. 2、代码质量管理平台
SonarQube是一个开源平台,用于管理源代码的质量.Sonar不只是一个质量数据报告工具,更是代码质量管理平台.支持的语言包括:Java、PHP、C#、C、Cobol、PL/SQL、Flex 等. 主要特点:
当然除了代码质量管理平台外,还有借助源代码管理系统,并且在每次提交代码前进行代码审核,这样每次代码的异动都可以追溯出来.我管理和经历过的一些重要系统中采用过这样的做法:除了管理所有程序代码之外,还将系统中数据库中的表、视图、函数及存储过程的创建都使用源代码版本管理工具管控起来,而且粒度很小,每个对象的创建都是一个SQL文件.这种方式虽然操作起来有些琐碎,但对于代码的变迁追溯非常方便. 三、系统性能保证1、缓存
缓存的实现方法:自定义实现或利用NoSQL.
自定义实现可利用SDK中提供的类,如Dictionary等. 优点:可以局部提高查询效率;
Memcached 优点:可以跨应用、跨服务器,有灵活的生命周期管理策略;支持高并发;支持分布式. Redis 优点:可以跨应用、跨服务器,有灵活的生命周期管理策略;支持高并发;支持集群;支持持久化;支持Key/Value、List、Set、Hash数据结构; 以上几种方法都存在一个特点:需要通过Key去寻找对应的Value、List、Set或Hash. 除了Memcached和Redis之外,还出现了一些NoSQL数据库和支持NoSQL的数据库,前者如MongoDB,后者如PostgreSQL(>V9.4),下面是一个MongoDB与PostgreSQL的NoSQL特性的对比: 文档型NoSQL数据库的特点:
即使不定义表结构,也可以像定义了表结构一样使用,还省去了变更表结构的麻烦.
NoSQL主要是提高效率,关系数据库可以保证数据安全;各有使用场景,一般的企业管理系统,没多少并发量没必要使用NoSQL,互联网项目或要求并发的NoSQL使用比较多,但是最终重要的数据还是要保存到关系数据库.这也是为什么很多公司会同时使用NoSQL和关系型数据库的原因. 2、异步
异步有两个层面:编程语言层面的异步和通过消息队列等机制实现的异步. 语法层面异步:像Java/C#等大多数语言都支持异步处理.
用消息队列实现异步只是消息队列的一个基本功能之一,消息队列还具有如下功能:
注:消息队列成为在进程或应用之间进行通信的最好形式.消息队列队列是创建强大的分布式应用的关键. 常用消息队列有如下,可根据系统特点和运维支持团队的掌握程度选择:
3、负载均衡
常见负载均衡方案 Windows负载均衡:NLB 前面几种都是免费的解决方案,F5作为一种硬件及解决方案在一般企业很少用到.我目前知道的仅有一家世界级饮料公司使用了F5作为负载均衡解决方案,因为这个方案据说相当昂贵. 4、读写分离
也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器;第二台数据库服务器,主要进行读的操作. 原理:让主数据库(master)处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库(slave)处理SELECT查询操作. 一般情况下我们是在代码中进行处理,但目前也有不少商业中间件形式的读写分离中间件,能自动将读写数据库操作调度到不同数据库上. 在大型系统中,有时候主、从数据库都是一个集群,这样可以保证响应速度更快,同时集群中单台服务器故障也不影响整个系统对外的响应. 四、系统安全性保证1、XSS攻击
XSS攻击类似于SQL注入攻击,攻击之前,我们先找到一个存在XSS漏洞的网站,XSS漏洞分为两种,一种是DOM Based XSS漏洞,另一种是Stored XSS漏洞.理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力,攻击代码也不局限于script.
DOM Based XSS是一种基于网页DOM结构的攻击,该攻击特点是中招的人是少数人.
Stored XSS是存储式XSS漏洞,由于其攻击代码已经存储到服务器上或者数据库中,所以受害者是很多人.假如有两个页面,一个负责提交内容,一个负责将提交的内容(论坛发帖、读帖就是这种形式的典型):
这样用户在a站提交的东西,在显示的时候如果不加以处理就会打开b站页面将相关敏感内容显示出来. 针对XSS攻击的防范办法:
2、SQL注入
所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令.在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击. 例如我们在登录一个系统时,在软件底层按照如下方式查询数据: 登录SQL语句:
针对SQL注入防范办法:
3、CSRF攻击
其核心策略是利用了浏览器Cookie或者服务器Session策略,盗取用户身份.
4、其它攻击
系统或者框架漏洞:如IIS6.0以下版本存在“JPG漏洞”;Apache Struts2服务在开启动态方法调用任意方法漏洞(CVE-2016-3081);OpenSSL的heartbeat漏洞(CVE-2014-0160);Apache解析漏洞;Nginx(<V0.8.37)空字节代码执行漏洞;IIS7.0及Nginx(<V0.8.37)畸形解析漏洞;文件上传漏洞;路径遍历漏洞;
下面是一些我见过的被攻击后的系统截图,如下图是CCTV音乐频道被攻击的截图: 还有本人2008年前后搭建PHPWind运行的画面: 上图中是本人2006年前后搭建的一个论坛,有人利用系统漏洞注册了很多用户名为空的用户(其实是身份遗失),然后又利用这些账户在论坛中大量发布广告、色情等违法违纪的帖子,因为使用了一些不可见字符进行注册的,在后台无法管理,最后只好在数据库中操作管理了. 五、开发相关的经验教训1、应用日志记录以前团队运维着一个老系统,系统中没有日志功能,而系统的操作人员的计算机水平又较低,每次打电话都是说系统不能用或者是一些根本无法快速定位原因的描述,每次接到求助后需要花费大量时间来分析定位原因,后来将系统中增加了日志功能,并且在网络状态连通情况下可自动将错误日志以邮件形式发送到负责同事组成的用户组,自此以后处理这类问题的响应时间大大缩短了,双方都很满意. 现在已经有很多开源日志库,比如.NET的Log4Net,Java的Log4j,可以很轻松地配置启用日志功能.利用日志组件可以将信息记录到文件或数据库,便于发现问题时根据上下文环境发现问题,这一点在调试多线程时尤其重要. 日志级别:FATAL(致命错误)、ERROR(一般错误)、WARN(警告)、INFO(一般信息)、DEBUG(调试信息). 注意:在调试环境中时日志级别尽量低(warn/info),在生产环境中日志级别尽量高(error),且对日志文件大小一定要进行控制.不然也会产生问题. 案例:某国内有名的管业集团公司的一个系统的重要模块发生问题,启用了日志功能以便通过日志组件快速将问题定位并修复.在发布到生产环境时,运行一段时间之后发现程序运行效率相当低下,多位开发人员对模块代码进行性能分析未发现问题,大家发现同样的数据量和操作在生产环境和开发环境效率差巨大,无意中发现生产服务器上日志文件已超过5G!事后发现是由于疏忽未调高日志级别且未对日志进行控制,调整日志模式为按日记录,问题解除. 参考:《log4net使用详解》 http://blog.csdn.net/zhoufoxcn/article/details/222053 2、历史记录追踪
尽可能使用代码管控工具对源代码进行管控,如SVN/TFS/Git,如果有可能不但管控程序代码,还要管控数据库相关的SQL文件(包括初始化脚本及存储过程和使用ORM框架中的Mapping文件),做到系统的一切变动皆有记录.
任何人提交代码都必须本人本地编译、调试无误后,再有人review后方可提交,且针对bug修复的提交需注明所修复的bug信息.
通过Bug记录系统记录整个bug的生命周期,包括发现、修复、关闭.TFS本身支持bug记录,开源系统中禅道也是一个不错的Bug记录工具. 六、总结本篇主要是就系统从开发到最终部署运维过程中常用的技术、框架和方法做了一个总结,当然以上经验总结来源于本人从业以来所经历的项目中的经验和教训,可能还有更好更完美的方案,在此权当抛砖引玉 原文来自微信公众号:DBAplus社群 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |