标签 网站架构 下的文章 - 酷游博客
首页
关于
友链
Search
1
阿里的简历多久可以投递一次?次数多了有没有影响?可以同时进行吗?
45 阅读
2
Java中泛型的理解
41 阅读
3
Java 14 发布了,再也不怕 NullPointerException 了!
38 阅读
4
Java中的可变参数
37 阅读
5
该如何创建字符串,使用" "还是构造函数?
30 阅读
技术
登录
/
注册
找到
2
篇与
网站架构
相关的结果
2025-01-22
pick王菊?作为“菊外人”的程序员能做点什么?
最近,想必大家的朋友圈都被“王菊”占领了,打开朋友圈到处可以见到“pick王菊”、“陶渊明”、“菊外人”等字眼,可谓是火的一塌糊涂。 作为一个“菊外人”的我“跟风”的去了解了一下到底是怎么回事儿。原来是最近很火的一个节目,大家都在呼吁给一个叫“王菊”的人投票。然后就有各种媒体发文分析“到底王菊是谁?”、“王菊为什么火了?”、“pick王菊给这个社会带来了什么?”等等文章。 但是,作为一个程序员,我们看这个世界的角度永远是那么的独特: 我们是那个浏览网页的时候经常会按ctrl + s的人。 我们是那个按下电梯的之后就会忍不住想电梯调度算法的人。 我们是那个每次支付宝付款的时候都会考虑二维码的生成逻辑的人。 不管是作为“菊外人”还是“陶渊明”,对于这个“pick王菊”事件,我们的角度是:如何实现一个高并发的投票系统? 我们需要一个怎样的投票系统?笔者分别浏览了目前创造101的各个投票通道,基本的要求有以下几个: 1、只有登录用户才能投票 2、每个用户投票数有限 3、不同用户可投票数不同,如Vip会比普通用户的票数多 4、投票是限时的,只有在有效时段内才能投票 除了以上几个功能性要求外,作为一个开发人员,还需要考虑以下几个非功能性需求: 1、计数要准确 2、可以处理高并发投票 3、可以处理大量的投票数据 4、要有很好的可用性 5、要把每个人的投票记录下来 登录验证 投票网站都是需要登录验证的,用户想要进行投票,需要先登录。目前很多大型网站的登录都采用单点登录(SSO,Single Sign On)技术,SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它是目前比较流行的企业业务整合的解决方案之一。 实现SSO的技术主要有以下几种: (1)基于cookies实现。 最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。但是存在几个问题;1、cookies并不安全,2、cookies本身不跨域。3、浏览器对cookies个数和大小有限制。但是,如果想要解决的话,以上三个问题还是可以找到方案的。只不过会让整个方案变得复杂而已。 (2) Broker-based(基于经纪人),例如Kerberos等;这种技术的特点就是,有一个集中的认证和用户帐号管理的服务器。经纪人给被用于进一步请求的电子的身份存取。中央数据库的使用减少了管理的代价,并为认证提供一个公共和独立的”第三方”。例如Kerberos,Sesame,IBM KryptoKnight(凭证库思想)等。Kerberos是由麻省理工大学发明的安全认证服务,当前版本V5,已经被UNIX和Windows作为默认的安全认证服务集成进操作系统。 (3) Agent-based(基于代理人)在这种解决方案中,有一个自动地为不同的应用程序认证用户身份的代理程序。这个代理程序需要设计有不同的功能。比如,它可以使用口令表或加密密钥来自动地将认证的负担从用户移开。代理人被放在服务器上面,在服务器的认证系统和客户端认证方法之间充当一个”翻译”。例如SSH等。 (4) Token-based,例如SecurID,WebID,现在被广泛使用的口令认证,比如FTP,邮件服务器的登录认证,这是一种简单易用的方式,实现一个口令在多种应用当中使用。 (5) 基于安全断言标记语言(SAML)实现,SAML(Security Assertion Markup Language,安全断言标记语言)的出现大大简化了SSO,并被OASIS批准为SSO的执行标准。开源组织OpenSAML 实现了 SAML 规范。可参考http://www.opensaml.org。 目前,很多大型网站都采用一个开源的SSO解决方案——CAS,CAS由耶鲁大学开发的单点登录系统(SSO,single sign-on),应用广泛,具有独立于平台的,易于理解,支持代理功能。 权限控制 在投票网站验证完用户的登录信息之后,紧接着会判断用户的权限,然后根据不同的权限来给用户分配不同的可投票次数。 关于权限的设计,一直是很多网站都要关心的问题。几乎所有的网站都会有一定的权限要求。 目前,关于权限设计大部分均采用RBAC理论(Role-Based Access Control),即基于角色的权限访问控制。 RBAC认为权限授权实际上是Who、What、How的问题。在RBAC模型中,Who、What、How构成了访问权限三元组,也就是“Who对What进行How的操作”。 一个简单的权限系统应该包含以下几个基本元素: 用户、角色、权限、资源、操作。 【用户】可以属于多个【角色】。【角色】可以认为是【权限】的合集。【权限】描述的是对【资源】的可【操作】能力。 比如在“pick王菊”这件事上,虽然大家都是“陶渊明”(王菊的粉丝自称陶渊明,因为陶渊明爱菊花),但是有些用户的角色是VIP用户,有些用户的角色是普通用户。VIP角色的用户在投票权限上就比普通用户更高。 限时开启 几乎所有的投票活动都是有一个起止时间的,只有在有效时间段内用户才可以参与投票。也就是说,当活动未开始的时候,用户来到投票页面,投票按钮应该是置灰无法点击的,有些网站还会给出倒计时的提示。 这其中就涉及到很多问题了。如何在时间到达时将按钮点亮呢?用户通过非法手段在有效时间外点击按钮如何处理?到时间后按钮又如何置灰? 一般情况下,用户访问的投票页面被设计为静态页面,被缓存在 CDN 与反向代理服务器中,甚至在用户的浏览器上。所以在投票活动未开始时,用户的刷新页面请求是不会到达应用服务器。同样,在后端的投票接口中,在接受到用户的投票请求时,也要做时间有效性的校验。 我们在秒杀商品的静态页面中加入一个 JavaScript 文件引用,它包含投票是否已开始的标志。秒杀开始时,系统会生成一个新的 JavaScript 文件,它会被浏览器加载(刷新页面或定时脚本),这样就能点亮页面中的购买按钮。这个 JavaScript 文件使用随机版本号,确保它不被浏览器、CDN 和反向代理服务器缓存。 同理,到达活动截止时间的按钮置灰也通过js引用的方式可以解决。 准确计数 对于一个投票系统来说,最重要的就是计数了。要保证在高并发的情况下用户的投票既不能多也不能少这是一个很大的挑战。 在“pick王菊”的投票中,计数场景有多处需要。比如对于王菊的票数需要准确的记录下来。还有,会员的已投票次数也要准确的记录下来。这里我们就拿被投票者的票数来举例。 基于MySql计数 我们能想到的最简单的方法就是在MySql数据库表中创建一条记录,记录当前被投票者的票数即可。如: CREATE TABLE IF NOT EXISTS `table_user_polls`( `id` INT UNSIGNED AUTO_INCREMENT, `user_id` bigint NOT NULL, `polls` bigint NOT NULL PRIMARY KEY ( `runoob_id` ) )ENGINE=InnoDB DEFAULT CHARSET=utf8; 当然,这只是一张记录总票数的表。当有用户投票的时候,我们通过修改表中的polls的值来进行: update table_user_polls set polls = polls +1 where user_id = "1000"; 当采用以上的update语句时,基本可以满足简单的票数的递增。但是,一旦有高并发场景的话,就无法满足了。因为多人同时执行这个语句的时候,就会有的人的更新结果丢失。 这时候,就需要引入锁机制来处理。比如我们增加乐观锁,改进后的update语句如下: update table_user_polls set polls = polls +1 where user_id = "1000" and polls = 1000000; 在更新table_user_polls表的polls字段的时候,我们先把表中当前的polls值取出,然后作为乐观锁来控制更新,如果发生并发,只会有一个请求可以更新成功。其他请求就会更新失败。 但是,紧接着又有两个问题来了。 数据量太大 如果数据量太大怎么办?比如这场“全民Pick王菊”的行动,参与的用户可能有很多很多,而我们要对每个用户的投票数据都持久化下来。这就涉及到一旦数据量过大,就会导致数据库的读写性能急剧下降。 传统的做法是进行分库分表,把投票表按照一定的维度进行拆分。比如这种投票的场景,我们可以按照投票的用户的userId拆分,对userId取模,根据结果存储到不同的表中。如把所有投票数据拆分到8个库128张表中,路由规则就是userId%128。 其实,这种单纯的分库分表还有一个另外的问题,虽然投票场景中可能涉及不到。1、热点数据问题。如多个热点用户的数据都分到了同一个库甚至同一张表中,就会又给数据库带来巨大压力。2、数据的二次分表问题。一旦分表数量不够了,就要再次分表。比如把128张表扩展到256张表,这就麻烦了,需要对原来的1287张表中的数据重新进行拆分,数据迁移到新的256张表中。 访问量太大 通过分库分表之后,我们暂时解决了数据量大的问题,那么如果遇到访问量大的问题怎么办。无论是我们的应用、服务器还是数据库等,能承受的QPS(TPS)都是有限的。如果峰值的qps超过了限制,就有可能导致整个系统瘫痪。 那么如何提高一个服务或者接口的QPS呢,其实一个最简单的方法就是降低响应时间(RT)。当然RT和QPS的关系还会受最佳线程数等影响,但是降低RT也是一个比较有效的办法。如果一个请求,在执行过程中,什么都不需要需要等待,每个操作都可以快速执行(如单纯的在内存中取数、计算等),那么RT就会低很多。 在程序中,导致请求阻塞的愿意可能有很多,数据库操作可能是其中比较重要的一部分。虽然我们通过分库的方式增加了数据库的连接数,但是直接操作数据库还是有很大的性能损耗的。 这时候,就要考虑在持久化存储前面增加缓存了。在访问数据库之前先访问缓存,如果缓存中没有的话再访问数据库。这样可以减少请求的响应时间,从而提高QPS,进而承载更大的访问量。 这样做有很大的好处,但是也不是完美的方案。比如这种投票系统,计数更新是非常频繁的,所以要经常失效缓存在重新缓存,缓存和数据库之间的数据一致性问题就体现出来了。 以上,是通过MySql来进行计数的方案,总结一下: 优点:便于理解、学习成本低、开发成本也低。 缺点:对大数据量和高并发量支持不友好。 基于Redis计数 Redis 是目前 NoSQL 领域的当红炸子鸡,它象一把瑞士军刀,小巧、锋利、实用,特别适合解决一些使用传统关系数据库难以解决的问题。 如果我们使用Redis来实现计数器的话,就相对来说简单一些了。因为Redid提供了一个INCR命令,其使用方法如下: redis> SET wangju_polls 20 OK redis> INCR wangju_polls (integer) 21 redis> GET wangju_polls "21" INCR key语法,可以将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。最重要的是INCR是一个原子性的自增操作。非常适合用来实现计数器。 引入了Redis之后,遇到高并发和大数据量的问题解决起来就简单了——堆机器。 当然,这个方案虽然在很大程度上解决了大数据量和高并发的问题。但是,如果真的是业务量特别巨大,总不能无限制的增加通过增加机器来解决问题吧,机器就是成本啊。 关于这种问题,微博就遇到了,因为微博的点赞功能和我们的投票功能其实是类似的。明星的一条微博的点赞数可能有几十万,甚至百万以上。有人(微博计数器的设计)算过一笔帐: 假设 key 为8字节,value为 4字节,通过incr存储的话: 一个 value 通过 createStringObjectFromLongLong 创建一个robj,由于value在LONGMIN 和LONGMAX 之间,所以可以将value用 ptr指针来存储,需要占用 sizeof(robj) = 16 字节; 一个key(即微博id) 最长64位数字(Eg: 5612814510546515491),但通过 sdsdup 以字符串的形式存储,至少需要 8(struct sdshdr)+19+1 = 28字节; 为了存到Redis 的dict里面,需要一个dictEntry对象,继续 3*8 = 24字节; 放到db->dict->ht[0]->table中存储dictEntry的指针,再要 8个字节; 存储一个64位key,32位value的计数,Redis也至少需要耗费: 16 + 28 + 24 + 8 = 76 字节。 1000亿个key全内存的话,就至少需要 100G * 76 = 7.6TB 的内存了(折算76G内存机器也需要100台!)。 我们的有效数据其实是 1000亿32位 = 400GB,但是却需要7.6TB来存储,内存的有效利用率约为: 400GB/7600GB = 5.3%. 总的来说,Redis做为优秀的内存数据结构,接口方便,使用简单,对于小型数据量的中高访问量的计数类服务来说,是一个很不错的选择,但是对于微博计数器这种极端的应用场景,成本还是无法接受! 所以,微博的点赞功能,其实是在Redis的基础上进行了二次开发。如在数据机构优化、转发和评论数 Value的优化、key的优化、数据的持久化、一致性保证等方面做了很多事情。这里不详细介绍了,感兴趣的同学可以参考微博计数器的设计 其他 避免刷票 在创造101的投票规则中,明确规定了:请公平参与点赞,如采用违法或违反赛事规则的点赞行为,将会被收回相关点赞数并追究责任。 那么,如果我们是这个投票系统的开发,如何有效的避免刷票行为呢? 首先,我们要通过设计一个很好的计数器,能够有效的避免高并发请求带来的计数错误。因为投票时可能有很多人使用脚本等构造多条请求,试图来突破限制来多投票。 其次,还可以通过一些其他限制手段来防止恶意刷票,如限制同一IP的投票次数、限制同一帐号的投票频率等。 避免数据溢出 据说,在前段时间的MSI比赛前期,MSI的助威活动中,人气选手uzi的票数达到了网站开发人员设置的int的最大值。 以上只是个传说,我并没有去辩证他的真伪,但是这至少给我们一个提醒,在设计投票系统的时候,要充分的考虑到粉丝们的热情和实力! 持久化数据的备份 无论最终选用那种方式进行计数,数据的持久化问题都至关重要,一定要做好数据存储的容灾工作。避免由于系统问题导致数据丢失。 PS:作者并没有在工作中开发过实际的投票系统,以上总结均是基于日常工作中的积累及一些参考资料总结得出。欢迎大家指正与讨论。 参考资料 [WeiDesign]微博计数器的设计(下) INCR命令 如何设计一套较完善的网络投票系统 SSO (Single Sign On)
技术
# 网站架构
酷游
1月22日
0
13
0
2025-01-22
大型网站架构技术一览
大型网站的挑战主要来自庞大的用户,高并发的访问和海量数据,任何简单的业务一旦需要处理数以P计的数据和面对数以亿计的用户,问题就会变得棘手。大型网站架构主要就是解决这类问题。更多内容也可以阅读各大互联网公司架构演进之路汇总、大型网站架构演化历程两篇文章。 本文内容大部分来自《大型网站技术架构》,这本书很值得一看,强烈推荐。 网站系统架构层次如下图所示: 1.前端架构 前端指用户请求到达网站应用服务器之前经历的环节,通常不包含网站业务逻辑,不处理动态内容。 浏览器优化技术 并不是优化浏览器,而是通过优化响应页面,加快浏览器页面的加载和显示,常用的有页面缓存、合并HTTP减少请求次数、使用页面压缩等。 CDN 内容分发网络,部署在网络运营商机房,通过将静态页面内容分发到离用户最近最近的CDN服务器,使用户可以通过最短路径获取内容。 动静分离,静态资源独立部署 静态资源,如JS、CSS等文件部署在专门的服务器集群上,和Web应用动态内容服务分离,并使用专门的(二级)域名。 图片服务 图片不是指网站Logo、按钮图标等,这些文件属于上面提到的静态资源,应该和JS、CSS部署在一起。这里的图片指用户上传的图片,如产品图片、用户头像等,图片服务同样适用独立部署的图片服务器集群,并使用独立(二级)域名。 反向代理 部署在网站机房,在应用服务器、静态资源服务器、图片服务器之前,提供页面缓存服务。 DNS 域名服务,将域名解析成IP地址,利用DNS可以实现DNS负载均衡,配置CDN也需要修改DNS,使域名解析后指向CDN服务器。 2.应用层架构 应用层是处理网站主要业务逻辑的地方。 开发框架 网站业务是多变的,网站的大部分软件工程师都是在加班加点开发网站业务,一个好的开发框架至关重要。一个号的开发框架应该能够分离关注面,使美工、开发工程师可以各司其事,易于协作。同时还应该内置一些安全策略,防护Web用攻击。 页面渲染 将分别开发维护的动态内容和静态页面模板集成起来,组合成最终显示给用户的完整页面。 负载均衡 将多台应用服务器组成一个集群,通过负载均衡技术将用户请求分发到不同的服务器上,以应对大量用户同时访问时产生的高并发负载压力。 Session管理 为了实现高可用的应用服务器集群,应用服务器通常设计为无状态,不保存用户请求上下文信息,但是网站业务通常需要保持用户会话信息,需要专门的机制管理Session,使集群内甚至跨集群的应用服务器可以共享Session。 动态页面静态化 对于访问量特别大而更新又不很频繁的动态页面,可以将其静态化,即生成一个静态页面,利用静态页面的优化手段加速用户访问,如反向代理、CDN、浏览器缓存等。 业务拆分 将复杂而庞大的业务拆分开来,形成多个规模较小的产品,独立开发、部署、维护,除了降低系统耦合度,也便于数据库业务分库。按业务对关系数据库进行拆分,技术难度相对较小,而效果又相对较好。 虚拟化服务器 将一台物理服务器虚拟化成多态虚拟服务器,对于并发访问较低的业务,更容易用较少的资源构架高可用的应用服务器集群。 3.服务层架构 提供基础服务,供应用层调用,完成网站业务。 分布式消息 利用消息队列机制,实现业务和业务、业务和服务之间的异步消息发送及低耦合的业务关系。 分布式服务 提供高性能、低耦合、易复用、易管理的分布式服务,在网站实现面向服务架构(SOA)。 分布式缓存 通过可伸缩的服务器集群提供大规模热点数据的缓存服务,是网站性能优化的重要手段。 分布式配置 系统运行需要配置许多参数,如果这些参数需要修改,比如分布式缓存集群加入新的缓存服务器,需要修改应用程序客户端的缓存服务器列表配置,并重启应用程序服务器。分布式配置在系统运行期提供配置动态推送服务,将配置修改实时推送到应用系统,无需重启服务器。 4.存储层架构 提供数据、文件的持久化存储访问与管理服务。 分布式文件 网站在线业务需要存储的文件大部分都是图片、网页、视频等比较小的文件,但是这些文件的数量非常庞大,而且通常都在持续增加,需要伸缩性设计比较好的分布式文件系统。 关系数据库 大部分万丈的主要业务是基于关系数据库开发的,但是关系数据库对集群伸缩性的支持表较差。通过在应用程序的数据访问层增加数据库访问的路由功能,根据业务配置将数据库访问路由到不同的物理数据库上,可实现关系数据库的分布式访问。 NoSQL数据库 目前各种NoSQL数据库层出不穷,在内存管理、数据模型、集群分布式管理等方面各有优势,不过从社区活动性角度看,HBase无疑是目前最好的。 数据同步 在支持全球范围内数据共享的分布式数据库技术成熟之前,拥有多个数据中心的网站必须在多个数据中心之间进行数据同步,以保证每个数据中心都拥有完整的数据。在实践中,为了减轻数据库压力,将数据库的事物日志(或者NoSQL的写操作Log)同步到其他数据中心,根据Log进行数据重演,实现数据同步。 5.后台架构 网站应用中,除了要处理用户的实时访问请求外,还有一些后台非实时数据分析要处理。 搜索引擎 即使是网站内部的搜索引擎,也需要进行数据增量更新及全量更新、构建索引等。这些操作通过后台系统定时执行。 数据仓库 根据离线数据,提供数据分析与数据挖掘服务。 推荐系统 社交网站及购物网站通过挖掘人与人之间的关系,人和商品之间的关系,发展潜在的人际关系和购物兴趣,为用户提供个性化推荐服务。 6.数据采集与监控 监控网站访问情况与系统运行情况,为网站运营决策和运维管理提供支持保障。 浏览器数据采集 通过在网站页面中嵌入JS脚本采集用户浏览器环境与操作记录,分析用户行为。 服务器业务数据采集 服务器业务数据包括两种,一种是采集在服务器端记录的用户请求操作日志;一种是采集应用程序运行期业务数据,比如待处理消息数目等。 服务器性能数据采集 采集服务器性能数据,如系统负载、内存使用率、网卡流量等。 系统监控 将前述采集的数据以图表的方式展示,以便运营和运维人员监控网站运行状况,做到这一步仅仅是系统监视。更先进的做法是根据采集的数据进行自动化运维,自动处理系统异常状况,是吸纳自动化控制。 系统报警 如果采集来的数据超过预设的正常情况的阀值,比如系统负载过高,就通过邮件、短信、语音电话等方式发出警报信号,等待工程师干预。 7.安全架构 保护网站免遭攻击及敏感信息泄露。 Web攻击 以HTTP请求的方式发起的攻击,危害最大的就是XSS和SQL注入攻击。但是只要措施得当,这两种攻击都是比较容易防范的。 数据保护 敏感信息加密传输与存储,保护网站和用户资产。 8.数据中心机房架构 大型网站需要的服务器规模数以十万计,机房物理架构也需要关注。 机房架构 对于一个拥有十万台服务器的大型网站,每台服务器耗电(包括服务器本身耗电及空调耗电)每年大约需要人民币2000元,那么网站每年机房电费就需要两亿人民币。数据中心能耗问题日趋严重,Google、Facebook选择数据中心地理位置的时候趋向选择散热良好,供电充裕的地方。 机柜架构 包括机柜大小,网线布局、指示灯规格、不间断电源、电压规格(是48V直流电还是220V民用交流电)等一系列问题。 服务器架构 大型网站由于服务器采购规模庞大,大都采用定制服务器的方式代替购买服务器整机。根据网站应用需求,定制硬盘、内存、甚至CPU,同时去除不必要的外设接口(显示器输出接口,鼠标、键盘输入接口),并使空间结构利于散热。
技术
# 网站架构
酷游
1月22日
0
21
0
易航博客