做了很多有关php 项目,其中包括(P2P、电商、配送、CRM、OA等)。我想对自己的工作成果经验总结一下,同时也算是一次升华。
项目中经常提到大流量和高并发的名词,听起来很让人害怕,无从下手,其实我们应该从实际的业务场景来规划应该如果去解决这些问题,正常情况下我们系统应该只是某个或者某几个服务压力非常大,其他业务负载不会太高,下面我从整体的架构来记录下思路,至于具体的实施方案,我在后续的文章会慢慢记录下来。
高并发大流量的系统架构应该是从单体架构到服务拆分逐渐演变而来,并不是一次就实现并解决所有问题。我觉得要架构一个高并发大流量的网站至少要从以下11个方面去考虑。
一、web服务容器选型
对于php系统项目来说,
①、选择nginx+php-fpm来作为我们的web容器,可以增加我们的并发连接数和处理效率,php-fpm和nginx默认选择9000端口进行通信,但是在流量大时我出现端口阻塞情况,所以我们改用本地socket进行通信。
②、nginx使用反向代理服务器,将流量转发到php-fpm服务器。
③、使用keepalived来对nginx代理服务器做高可用。
二、服务拆分、分布式集群部署
我们对整体系统进行需求分析后,可以将功能的模块分开然后做成一个独立的系统来进行服务,然后将这些独立的服务进行集群部署,就形成了我们的分布式集群解决方案。
比如我们做电商系统现有:用户模块、商品模块、订单模块、支付模块、消息模块、物流信息模块、仓库模块等。我们可以将这些模块独立出来然后拆分为用户服务、商品服务、订单服务、支付服务、消息服务、物流信息服务、仓库服务等。这从系统层面就实现了解耦,降低了代码后期维护的难度,提高了服务器的响应。
但这样做会衍生出三个问题:
①、系统的复杂度变高。
②、排查问题和异常变的异常复杂。
③、日志无序,分析问题变得困难。
怎么解决上面的问题呢?下面我们会慢慢阐述。
php常用六大设计模式:https://blog.csdn.net/jeremy_ke/article/details/89000003(转载)
php数组底层实现:https://www.cnblogs.com/mzhaox/p/11295445.html(转载)
三、缓存架构选型
我们现在主流的缓存是使用redis来做,因为redis是单线程的内存操作,不消耗磁盘I/0,所以它单机正常情况下能达到10W/s的读写操作,它能解决高并发情况下的并发锁和读写效率慢的问题。虽然这么优秀,但单机redis会存在单点故障,所以我们在选型的时候会选择 以下两种方案来保证redis的高可用。
①、一主多从 + 哨兵模式。
②、redis 集群模式,集群至少是3主3从才能搭建,而且可以动态扩容和分槽。
四、mysql数据库架构选型
上面说到了我们将多个功能模块拆分为多个服务后,那数据库怎么处理呢? 我们也使用分散方法,将不同的服务对应的数据库放在不同的物理机下面,增加数据库读写(I/O)能力。同时为了保证数据库的高可用,我们应该采用一主多从或者多主多从的做法来提高我们数据库的能力,更高层面的是采用异地多活(目前还未做过异地多活)。
MySQL双主双从同步配置:https://www.cnblogs.com/h--d/p/13336776.html(转载)
五、数据库优化
数据库的优化是非常复杂且难做到的事情。我平时主要从以下几个方面来做。
①、查询SQL优化,尽量命中索引,重要SQL 语句一定要使用explain来做查询预分析。
②、数据表建立合适的索引,提升查询效率,innodb每个表都要自己创建主键,如果我们不创建主键,mysql自己也会创建一个隐藏的主键。
③、设置好innodb_buffer_poll_size的值。
④、设置好innodb_log_buffer_size的值。
⑤、选择合适的innodb 事务隔离级别。
⑥、弄清楚innodb binlog日志与数据对磁盘的使用,找到合适的存储方法。
⑦、熟悉innodb的存储原理,提升磁盘I/O的率用率。
MySQL性能调优(存储优化) :https://blog.csdn.net/dichengyan0013/article/details/102347220(转载)
六、前端优化(前后端分离)
前端我想到的只有三点。
①、减少dom树的渲染,使用vue.js开发。
②、减少http请求数,将css和js文件使用npm压缩,减少带宽。
③、使用cdn缓存技术。
七、消息队列
对于大批量的数据处理,比如秒杀订单或者发送短信、邮件这些,我们都需要用到消息队列,不管是redis 还是 kafka,都是实现消息的一种方式,我们需要根据具体业务场景选择使用哪种消息队列来实现业务上的解耦。
kafka中文文档:https://www.orchome.com/66(转载)
kafka什么时候会丢消息:https://blog.csdn.net/qrne06/article/details/94225070(转载)
kafka最全面试题: https://blog.csdn.net/qq_34668848/article/details/105611546(转载)
zookeeper是干什么的:https://www.cnblogs.com/ultranms/p/9585191.html(转载)
八、服务器监控
服务拆分后我们对服务器的运行情况和性能监控的掌握尤其应该注意,如果某个服务集群中的某台服务器出问题,我们怎么来进行定位问题,或者某台服务器负载过高,我们怎么知道,这些都需要监控来告诉我们。我们一般采用grafana + prometheus 对服务器进行监控和报警。
九、全链路日志
拆分成多个服务后,我们需要顺序的记录某次请求的所有日志,对我们分析线上问题来说将会提供极大便利。如果没有统一存储日志,我们就需要到每台服务器去查询日志,而且不知道哪个环节出问题,大大增加我们排查问题的难度。我们项目中一般使用ELK(elasticsearch、Logstash、Kibana) 来收集和处理日志。
十、基于swoft或者swoole的多进程框架
上面我们讲述的是分布式集群的解决方案,随着大数据时代的来临,数据量的处理越来越大,我们大PHP 也有力不从心的时候,因为是单线程处理,限制了我们的处理能力,多线程对PHP来说支持的也不是很好,所以大佬们纷纷贡献了 swoole 和 swoft 框架,其实swoft也是基于swoole去开发的,现在说一下这两个框架吧。
swoole是一个用c++编写的高性能、异步、协程框架,它算是一个底层框架了,基于它人们又开发出了easyswoole、Hyperf等。
swoft也是一个基于swoole作为开发的框架,它完美的模仿了java spring的 ioc和aop 以及注解,增加了服务的注册与发现、服务的熔断、降级与限流,是非常好的php 多进程、多线程、协程 框架。
十一、并发压力测试
压力测试内容很多,这里就不细说了,大家可以在百度去搜索。
写的很简陋,至少我自己知道思路,朝着思路向前走。