高并发解决方案(下)

五、建立独立的图片服务器

    独立的图片服务器有诸多好处,其中一个就是客户端浏览器对一个主机下的连接数量限制,具体的连接数目忘记了,但基本都在10以下。也就是说,浏览器会控制一个站点下的并发请求数量在10以下,如果对于网站有很多样式文件、脚本文件和图片需要加载的话,请求的过程会被阻塞,影响网站的打开速度。  

      建立图片服务器,将图片资源放在另外一个域名下面,会在一定程度上提升网站的打开速度,这样来说的话是不是说我们独立的服务器越多越好呢?也不尽然,解析域名并建立连接也需要很长的时间,独立的主机多了的话,也不利于速度的提升。

      图片往往会消耗掉网站中的很多宽带和IO资源,独立的图片服务器可以在宽带和IO性能上单独提升,便于管理和拓展。

六、动态语言静态化

请求动态内容:

php –>域名->DNS解析找到对应ip地址->返回给客户端->客户端找到真实的服务器->80端口web服务->nginx 判断是否为php->反向代理->php-fpm PHP解析器->php代码内容解析->html代码->浏览器

什么是动态语言静态化?

  将现有PHP等动态语言的逻辑代码生成为静态HTML文件,用户访问动态脚本重定向到静态HTML文件的过程,适合用于对实时性要求不高的页面

为什么要静态化?

  动态脚本通常会做逻辑计算和数据查询,访问量越大,服务器压力越大

  访问量大时可能会造成CPU负载过高,数据库服务器压力过大静态化可以减低逻辑处理压力,降低数据库服务器查询压力。

静态化的实现方式

   1.使用模板引擎:常见的模板引擎可以使用Smarty,Smarty的缓存机制生成静态HTML缓存文件

$smarty->cache_dir = $ROOT."/cache"; //缓存目录
$smarty->caching = true; //是否开启缓存
$smarty->cache_lifetime = "3600"; //缓存时间
$smarty->display(string template[,string cache_id[,string compole_id]]);
$smarty->clear_all_cache();//清除所有缓存
$smarty->clear_cache('file.html'); //清除指定的缓存
$smarty->clear_cache('article.html',$art_id);//清除同一个模板下的指定缓存好的缓存

  2.利用ob系列的函数

ob_start();//打开输出控制缓冲
ob_get_contents(); //返回输出缓冲区内容
ob_clean(); //清空输出缓冲区
ob_end_flush(); //冲刷出(送出)输出缓冲区内容并关闭缓冲

//示例

ob_start();
输出到页面的HTML代码...

ob_get_contents();
ob_end_flush();
fopen() 写入

//1.判断当前文件是否有修改,2.判断是否存在缓存文件 3.判断缓存文件是否过期
<?php
$cache_name  = md5(__FILE__).'.html';

$cache_lifetime = 3600;//缓存时间

if(filectime(__FILE__) <= filectime($cache_name)&&file_exists($cache_name) && filectime($cache_name)+ $cache_lifetime > time() ){
    include $cache_name;
    exit;
}

ob_start();

?>

<b>html 代码</b>

<?php
$content = ob_get_contents();

ob_end_flush();

$handle = fopen($cache_name, 'w');

fwrite($handle,$content);
fclose($handle);


//根据id 做不同缓存
$id = $_GET['id'];
if(empty($id)){
$id = '';
}
$cache_name = md5(__FILE__). '-'.$id.'.html';

七、动态语言并发处理

在了解并发处理之前需要了解相关概念:

  什么是进程、线程、协程

  什么是多进程、多线程

  同步阻塞模型

  异步非阻塞模型

进程:

  进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构中的基础     进程是一个“执行中的程序”

  进程的三态模型:运行、就绪、阻塞

  进程的五态模型:新建态、终止态、活跃就绪、静止就绪、活跃阻塞、静止阻塞

  参考:https://www.cnblogs.com/xiawen/p/3328033.html

线程:

  线程是程序中一个单一的顺序控制流程。进程内一个相对的、可调度的执行单位,是系统独立调度和分派CPU的基本单位

  线程的状态: 参考:https://blog.csdn.net/kzadmxz/article/details/73437926

协程

     参考:http://www.sohu.com/a/237171690_465221 

进程与线程的区别:

1.线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间

2.进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源

3.线程是处理器调度的基本单位,但进程不是

4.二者均可并发执行

5.每个独立的线程有一个程序的运行的入口,顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多线线程执行控制

线程与协程的区别:

1.一个线程可以拥有多个协程,一个进程也可以单独拥有多个协程

2.线程进程都是同步机制,而协程则是异步

3.协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

多线程多进程:

https://zhidao.baidu.com/question/282409258.html

同步、异步、阻塞、非阻塞

https://www.cnblogs.com/George1994/p/6702084.html

了解完以上相关概念后,php相关的并发编程有哪些呢?

PHP的swoole拓展

  swoole是php的异步、并行、高性能网络通信引擎,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询,除了异步IO的支持之外,Swoole为PHP多进程的模式设计了多个并发数据结构和IPC通信机制,可以大大简化多进程并发编程的工作

消息队列

  常见消息队列产品:Kafka、ActiveMQ、ZeroMQ、RabbitMQ、Redis等

  应用场景:

  注册:将注册信息写入数据库成功后,将成功信息写入队列,此时直接返回成功给用户,写入队列的时间非常短,可以忽略不计,然后异步发送邮件和短信

  下单:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功,订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息进行库存操作

  秒杀活动:用户瞬时激增,用户发起请求,服务器接收后,先写入消息队列,假如消息队列长度超过最大值,则直接报错或提示用户

  解决大量日志的传输:日志采集程序将程序写入消息队列,然后通过日志处理程序的订阅消费日志

  聊天室:多个客户端订阅同一主题,进行消息发布和接收

接口的并发请求

  curl_multi_init

八、数据库缓存优化

 什么是数据库缓存?

  MySQL等一些常见的关系型数据库的数据都存储在磁盘当中,在高并发场景下,业务应用对MySQL产生的增、删、改、查的操作造成巨大的I/O开销和查询压力,这无疑对数据库和服务器都是一种巨大的压力,为了解决此类问题,缓存数据的概念应运而生。

  常见的缓存形式:内存缓存,文件缓存

 为什么要使用缓存?

  缓存数据是为了让客户端很少甚至不访问数据库服务器进行数据的查询,高并发下能最大程度地降低对数据库服务器的访问压力

用户请求-->数据查询-->连接数据库服务器并查询数据-->将数据缓存起来(HTML、内存、JSON、序列化数据)-->显示给客户端

用户再次请求或者新用户访问-->数据查询-->直接从缓存中获取数据-->显示给客户端

  

 MySQL的查询缓存

  query_cache_type

  查询缓存类型,有0 1 2三个取值,0则不使用查询缓存,1表示始终使用查询缓存,2表示按需使用查询缓存

  query_cache_type 为1时,亦可关闭查询缓存

  SELECT SQL_NO_CACHE * FROM my_table WHERE condition;

  query_cache_type为2时,可按需使用查询缓存

  SELECT SQL_CAHCE * FROM my_table WHERE condition;

  query_cache_type为0时,表示为查询缓存预留的内存为0,则无法使用查询缓存

  SET GLOBAL query_cache_size = 134217728

  查询缓存可以看做是SQL文本和查询结果的映射

  第二次查询的SQL和第一次查询的SQL完全相同,则会使用缓存SHOW STATUS LIKE 'Qcache_hits';查看命中次数

  表的结构或数据发生改变时,查询缓存中的数据不再有效

清理缓存:

  FLUSH QUERY CACHE;  //清理查询讯缓存内存碎片

  RESET QUERY CACHE; //从查询缓存中移出所有查询

  FLUSH TABLES; //关闭所有打开的表,同时该操作将会清空查询缓存中的内容

使用Memcache缓存查询数据

  对于大型站点,如果没有中间缓存层,当流量打入数据库层时,即便有之前的几层为我们挡住一部分流量,但是在大并发的情况下,还是会有大量请求涌入数据库层,这样对于数据库服务器的压力冲击很大,响应速度也会下降,因此添加中间缓存层很有必要

  memcache是一套分布式的高速缓存系统,对于一些大型的、需要频繁访问数据库的网站访问速度提升效果十分显著

  工作原理:

  memcache是一套高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存,然后从内存中读取,从而大大提高读取速度

  工作流程:

  先检查客户端的请求数据是否在memcached中,如有,直接把请求数据返回,不再对数据库进行任何操作;如果请求的数据不再memcached中,就去查数据库,把从数据库中获取的数据返回给客户端,同时吧数据缓存一份到memcached中

  方法:获取:get(key)  设置:set(key,val,expire) 删除:delete(key)

  通用缓存机制: 用查询的方法名+参数作为查询时的key value对中的key值

使用Redis缓存查询数据

  与Memcahce 的区别:

  性能相差不大

  Redis在2.0版本后增加了自己的VM特性,突破物理内存的限制,Memcache可以修改最大的可用内存,采用LRU算法

  Redis,依赖客户端来实现分布式读写,Memcache本身没有数据冗余机制

  Redis支持(快照、AOF)依赖快照进行持久化,aof增强了可靠性的同时,对性能有所影响

  Redis用于数据量较小的高性能操作和运算上 Memcache用于在动态系统中减少数据库负载,提升性能;适合做缓存,提高性能

  

九、Mysql数据层优化

数据表数据类型优化

  字段使用什么样的数据类型更合适

  字段使用什么样的数据类型性能更快

  tinyint  smallint    bigint   --- 考虑空间的问题,考虑范围的问题

  char varchar   --- 存储字符长度是否固定

  enum ---  特定、固定的分类可以使用enum存储,效率更快

  ip地址的存储  使用整型存储ip地址

索引优化

  建立合适的索引

  索引在什么场景下效率最高

  索引不是越多越好,在合适的字段上创建合适的索引

  复合索引的前缀原则   ---Abc三个字段复合索引  查询条件为a AND b 可以 b AND c a AND c 不可以

  like查询%的问题    ---like 百分号在前索引失效

  全表扫描优化     ---全表扫描自动失效 

  or条件索引使用情况         --- Or 前面有后面无则索引失效

  字符串类型索引失效问题  ---  字符串查要加引号

SQL语句的优化

  优化查询过程中的数据访问    ---使用limit  返回列不用*

  优化长难句的查询语句  ----变复杂为简单   切分查询    分解关联查询   分次删除   

  优化特定类型的查询语句  ---优化count()   优化关联查询 优化子查询 优化GROUP BY 和distinct 优化limit和union

存储引擎的优化

  1、MyISAM:默认表类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,而且不支持外键,如果执行大量的select,insert MyISAM比较适合。

  2、InnoDB:支持事务安全的引擎,支持外键、行锁、事务是他的最大特点。如果有大量的update和insert,建议使用InnoDB,特别是针对多个并发和QPS较高的情况

参考 https://www.cnblogs.com/y-rong/p/8110596.html

数据表结构设计的优化

  分区操作:通过特定的策略对数据表进行物理拆分   对用户透明  partiton by

  分库分表:水平拆分(活跃数据和不活跃数据 union)  垂直拆分(常用和不常用列 join)

数据库服务器架构的优化

  主从复制

  读写分离

  双主热备

  负载均衡

十、MySQL的负载均衡 web服务器负载均衡 

MYSQL负载均衡: 通过LVS的三种基本模式实现负载均衡 MyCat数据库中间件实现负载均衡

web服务器负载均衡七层负载均衡的实现  四层负载均衡的实现

原文地址:https://www.cnblogs.com/ygtup/p/10430727.html