阶段性总结及知识点整理
数据回补
- 程序运行中由于未知原因造成的数据读出不一致的情形,在排查和确认代码和接口符合要求的情况下,通过手动代替定时任务调用一次相应方法,重新获取一遍数据,覆盖之前误读内容。
- 不能直接人为改动线上数据。
SSO单点登录
- 微博的Web应用服务器是无状态的,用户的登录状态信息由专门的服务器管理,sso sdk 为业务层提供了一套统一的标准的获得用户登录状态等信息的方法,SSOClient代码包对sdk作了进一步封装,供业务代码调用,屏蔽了底层实现,相应文件部署在php include path中。
- 业务层代码只负责调用SSOClient中的方法,不关心实现,体现了封装性。获得当前用户登录状态信息等通用方法被抽象出来在基类中实现,体现了继承性。
- 票据ticket作为凭证,当应用需要用户登录时,用户输入用户名密码到sso服务器进行验证并获取票据,并将票据转交应用程序,应用程序向sso服务器发送票据,验证其有效性,并完成登录。这样的设计避免了用户直接将用户名密码信息发送到应用服务器,一是安全性,二是低耦合。
- 整个体系中类似还有独立的文件服务器集群、应用服务器集群、数据库服务器集群、缓存服务器集群等。这样的架构设计使得整个Web服务具有很强的伸缩性和可扩展性。
异构共存
- Web服务体系本身就属于异构共存的架构体系,优点是能充分利用各种程序语言的优势特点,模块之间低耦合高聚合;缺点是彼此之间服务模型不同,行为特点不同,差异明显,比如php单进程同步阻塞,nodejs单线程异步非阻塞,python、java多线程,直接相互调用不易实现。
解决异构共存问题关键在于通信协议和数据传输格式。只要暴露接口,按照约定的协议和规范的数据传输格式就能实现彼此之间的消息通信,比如http协议、sinaweibo协议、json的数据格式等。将消息实体序列化之后在网络中进行传输,到达目的后再反序列化解析和处理。
Http / Https协议
- Http基于TCP/IP,建立连接前要通过三次握手来保证连接可靠性,本身属于无状态的连接,即上下文无关,请求的代价比较昂贵,往往带上一长串请求头,其中包括能表明客户端用户身份的cookie信息等,1.0版本一次成功连接只能发送一个请求,1.1版本中keep-alive值设置为true,即使用了长连接,多次请求时可复用建立好的连接。因此,在网站性能优化方面,可以:
- 通过减少请求次数,如合并压缩css文件、js文件;
- 通过减少传输数据的大小,节省带宽,提高传输速率,如压缩、base64encode、使用ajax方式;
- 动静分离,对静态资源的请求附上cookie信息一般是没有必要的,而且占用带宽,一般将静态资源部署到独立的域名下。
- Https建立在tls/ssl上,应用非对称加密机制,由CA签名颁发和验证证书,进行双向认证,保证数据在传输过程中安全性,防止中间人冒充服务端或客户端角色,窃取数据,影响正常服务。证书从根目录逐级向下颁发,浏览器一般能够预置CA机构颁发的证书,但对于自签名的证书不享有此权利,双向安全认证这一过程也使得Https较Http更加耗时。
- WebSocket属于Http的升级协议。实现这样一个连接同样先经历三次握手,成功后再进行协议切换成功后开始数据传输。Http属于短连接,WebSocket属于长连接,全双工通信,适合于做服务器端的消息推送,当然有情况下可能不能使用WebSocket,如浏览器不支持,一般这种情况下都会有降级策略如长轮询等。
- Http2.0,在应用层和传输层之间加入了一个二进制分帧,实现多路复用,一次连接可实现多次并发请求。
数据库容灾备份策略
- 主从热备:至少部署两台数据库服务器构成集群,配置主从关系。一方面可以实现读写分离提高效率,一方面当某一台服务器宕机无法使用时,可随时切换到另外的可用设备,不致使数据丢失或服务不可用,保障web服务的高可用性。
流程
- 代码发布:分支开发,主干合并、测试、回归、上线、(出现问题)回滚。
- 用到缓存服务、数据库服务、Mcq服务等时,须申请相关资源:申请、备案、使用、注销。申请资源空间大小时需要事先进行估算,选择合适的空间。
监控
- 良好的监控是网站应用高性能的重要保证。也为性能分析提供重要依据。
- 对超时等异常行为进行自动报警,邮件通知。及时响应。
- 日志记录相关数据。事后分析处理。
调试
- Php调试比较简单方便,开发速度快,可以在任意位置进行输出打印变量或者终止程序。
- 对于5xx错误,即服务器端发生的错误:
- 502 Bad Gateway,不一定是nginx服务器的问题,也有可能是php-fpm没有开启;
- 500 服务器内部错误,代码的错误,可以通过查看log日志,迅速对出错代码行进行定位。
- 对于数据不一致等输出与预期不符的问题:
- 检查是否有缓存;
- 检查是否有排序,排序是否正确;
- 尝试手动调用程序中调的其他内部接口,查看输出情况,以此检查程序在调用接口处理数据时是否有没有考虑的情况。
- 打印变量值,重新走一遍代码逻辑,查看是否有错误的地方,如语句写到了条件判断或循环之外等。
优化
- 配置文件加载到内存变量中:某些业务代码执行中需要频繁地读取配置文件,涉及到大量的I/O操作,从而成为网站性能瓶颈,因此可以在一开始便将这些配置文件读入内存,保存在静态变量中,之后只需读取和处理内存中变量即可。
- 使用合适的数据结构:
eg:使用int型数据保存多选项,int型数据占4字节32位,如一个至多31天,记录某人当月签过到的日子可以在对应位置1,进行位运算得出。
Mcq消息队列
- 生产者/消费者模型。异步操作,非阻塞模式,能很好地应对高并发访问情形。了解微博中Mcq消息队列实现原理及启动方式。
- 微博中使用的Mcq消息队列,加入了时间信息,能够超时报警;由一个监控Monitor进程和多个Mcq具体实现进程共同构成,并进行心跳检测、自动重启、自动化报警,监控进程类似于服务daemon,MemcacheQ用作队列存储,监控进程与Mcq进程通信走Mc或数据库。
注:Redis同样能够用作消息队列,其处理性能估计也不亚于Mcq,但是目前没有对Redis队列完整成熟的监控体系。对于大型网站应用而言,良好的监控是保证高性能的关键之一。
Cron Tasks定时任务
- 掌握Linux下cron任务的用法、各参数所代表含义等。
- Yaf框架在Cli模式,即命令行下启动php脚本的方法。利用crontab工具,定时执行php脚本。
缓存与数据库
- 一致性哈希原理及延伸:缓存服务器集群的线性伸缩,向集群中增减服务器带来的缓存重新分配的影响、缓存命中与失效。
- 缓存读写一般在内存中直接完成,数据库读写一般要通过I/O操作,CPU直接跟内存打交道,所有磁盘数据要读入内存才能被CPU计算处理,因此缓存比数据库速度更快,数据读写比至少2:1才有缓存价值,实际应用中远远高于这个值。
- 数据库索引文件存储:Mysql的Innodb引擎采用B+ tree对索引进行存储,利用linux分页预读机制,每个node设置成一页的大小,以减少I/O读写操作的耗时,一般树不超过3层。机械硬盘随机读写性能较差,固态硬盘随机读写性能较好,有助于提高数据库读写效率。
- 索引设计:适合在经常排序、查询的一个或多个字段上建立,字段值域不能太窄。
- 分表:一般按关键字哈希分表,也有时候按时间粒度分,根据业务实际情况分表,防止创建的索引树的高度过高需要频繁的进行I/O操作从而影响数据库读写性能,另外历史性的数据使用频率较低,与常用数据存储在同一张表中也降低了整体性能,可以分离出去。
降级策略
- 当并发访问量高,易发生网络拥塞的情况下,保证核心业务可用,可适当减少非核心业务所占带宽。
- 应当尽量不影响或尽可能少地影响正常用户体验。
- 可制定多种备选方案,视具体情况选择合适的方案。
版本控制
- 数据库和缓存(Memcached)控制:防止数据脏读脏写。
- 代码控制:版本控制器如svn,冲突检测与解决。
- 线上发布控制:js,css等静态资源一般缓存在CDN运营商的服务器中,处于离用户最近的位置,一般这类文件都会带上版本号,防止新发布的代码无法到达用户。
乐观锁机制。
查看与分析网络请求
- PC、移动端的web页请求,即走http/https的请求均可用Chrome查看与调试。
- 客户端Page Card等请求,即走sinaweibo协议的请求可设置代理,在电脑上通过抓包工具进行分析。
性能分析方法
- 利用xhprof扩展对php脚本运行性能进行分析
- 压力测试工具,如ab
- 编写shell脚本分析运行效率等情况