Deprecated
: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in
/www/wwwroot/testblog.58heshihu.com/var/Widget/Archive.php
on line
1057
首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
182 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
28
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
9
篇与
的结果
2023-08-28
PHP实现异步调用方法研究
PHP实现异步调用方法研究浏览器和服务器之间是通过 HTTP 协议进行连接通讯的。这是一种基于请求和响应模型的协议。浏览器通过 URL 向服务器发起请求,Web 服务器接收到请求,执行一段程序,然后做出响应,发送相应的html代码给客户端。这就有了一个问题,Web 服务器执行一段程序,可能几毫秒就完成,也可能几分钟都完不成。如果程序执行缓慢,用户可能没有耐心等下去,就关闭浏览器了。而有的时候,我们更本不关心这些耗时的脚本的返回结果,但却还要等他执行完返回,才能继续下一步。那么有没有什么办法,只是简单的触发调用这些耗时的脚本然后就继续下一步,让这些耗时的脚本在服务端慢慢执行?经过试验,总结出来几种方法,和大家share:1. 最简单的办法就是在返回给客户端的HTML代码中,嵌入AJAX调用,或者,嵌入一个img标签,src指向要执行的耗时脚本。这种方法最简单,也最快。服务器端不用做任何的调用。但是缺点是,一般来说Ajax都应该在onLoad以后触发,也就是说,用户点开页面后,就关闭,那就不会触发我们的后台脚本了。而使用img标签的话,这种方式不能称为严格意义上的异步执行。用户浏览器会长时间等待php脚本的执行完成,也就是用户浏览器的状态栏一直显示还在load。当然,还可以使用其他的类似原理的方法,比如 script 标签等等。2. popen()resource popen ( string command, string mode );//打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。所以可以通过调用它,但忽略它的输出。pclose(popen("/home/xinchen/backend.php &", 'r'));这个方法避免了第一个方法的缺点,并且也很快。但是问题是,这种方法不能通过HTTP协议请求另外的一个WebService,只能执行本地的脚本文件。并且只能单向打开,无法穿大量参数给被调用脚本。并且如果,访问量很高的时候,会产生大量的进程。如果使用到了外部资源,还要自己考虑竞争。3. 使用CURL这个方法,设置CUROPT_TIMEOUT为1(最小为1,郁闷)。也就是说,客户端至少必须等待1秒钟。$ch = curl_init(); $curl_opt = array(CURLOPT_URL, 'http://www.example.com/backend.php', CURLOPT_RETURNTRANSFER, 1, CURLOPT_TIMEOUT, 1,); curl_setopt_array($ch, $curl_opt); curl_exec($ch); curl_close($ch);4. 使用fsockopen这个方法应该是最完美的,但是缺点是,你需要自己拼出HTTP的header部分。$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = "GET /backend.php / HTTP/1.1\r\n"; $out .= "Host: www.example.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); /*忽略执行结果 while (!feof($fp)) { echo fgets($fp, 128); }*/ fclose($fp); }所以,总体来看,最好用,最简单的还是第一种方法。最完美的应该是最后一种,但是比较复杂
2023年08月28日
14 阅读
0 评论
0 点赞
2023-08-28
PHP异步编程: 手把手教你实现co与Koa
PHP异步编程: 手把手教你实现co与Koa
2023年08月28日
20 阅读
0 评论
0 点赞
2023-08-10
PHP异步编程简述
PHP异步编程简述概述异步编程,我们从字面上理解,可以理解为代码非同步执行的。异步编程可以归结为四种模式:回调、事件监听、发布/订阅、promise模式。我们最熟悉的两种模式是回调和事件监听,举两个最简单的javascript例子,一个ajax,一个点击事件的绑定:123$.getJSON("uri", params, function(result) {do_something_with_data(result);});123$("#id").click(function(){do_something_when_user_click_id();});以上两个示例有一个共同的特点,就是把函数当做参数传递给另一个函数。被传递的函数可以被称作为闭包,闭包的执行取决于父函数何时调用它。优势与劣势异步编程具有以下优势:解耦,你可以通过事件绑定,将复杂的业务逻辑分拆为多个事件处理逻辑并发,结合非阻塞的IO,可以在单个进程(或线程)内实现对IO的并发访问;例如请求多个URL,读写多个文件等效率,在没有事件机制的场景中,我们往往需要使用轮询的方式判断一个事件是否产生异步编程的劣势:异步编程的劣势其实很明显——回调嵌套。相信一部分人在写ajax的时候遇到过这样的场景:1234567$.getJSON("uri", params, function(result_1) {$.getJSON("uri", result_1, function(result_2) { $.getJSON("uri", result_2, function(result_3) { do_something_with_data(result_3); }); });;});这样的写法往往是因为数据的依赖问题,第二次ajax请求依赖于第一次请求的返回结果,第三次ajax依赖于第二次。这样就造成深层次的回调嵌套,代码的可读性急剧下降。虽然有一些框架能够通过一些模式解决这样的问题,然并卵,代码的可读性相比同步的写法依然差很多。异步编程的另一个劣势就是编写和调试的过程更加复杂,有时候你不知道什么时候你的函数才会被调用,以及他们被调用的顺序。而我们更习惯同步串行的编程方式。然而,我相信一旦你开始使用异步编程,你一定会喜欢上这种方式,因为他能够带给你更多的便利。PHP异步编程概述在php语言中,异步的使用并不像javascript中那么多,归其原因主要是php一般是在web环境下工作,接收请求->读取数据->生成页面,这看起来天生就是一个串行的过程;所以,在php中,异步并没有广泛使用。在javascript中的4中异步编程模式,均可以在php中实现。回调:1234array_walk($arr, function($key, $value){$value += 1;});print_r($arr);回调的方式,在大多情况下,代码仍然是顺序执行的(array_walk->print_r的顺序)。回调函数的意义在于被传递者可以调用回调函数对数据进行处理,这样的好处在于提供更好的扩展性和解耦。我们可以把这个回调函数理解为一个格式化器,处理相同的数据,当我传递一个json过滤器时,返回的结果可能是一个json压缩过的字符串,当我传递的是一个xml过滤器时,返回的结果可能是一个xml字符串(有点多态的思想)。事件监听(定时器,时间事件):12345678$loop = React\EventLoop\Factory::create();$loop->addPeriodicTimer(5, function () {$memory = memory_get_usage() / 1024; $formatted = number_format($memory, 3).'K'; echo "Current memory usage: {$formatted}\n";});$loop->run();事件监听在PHP中用的并不多,但并不是没有,例如pcntl_signal()监听操作系统信号,以及其他IO事件的监听等等。上面的示例是一个事件事件的侦听,每隔5s中,会执行一次回调函数。在四种异步模式中,事件监听的应用是更有意义的。然我们看一个同步的例子,下面这段代码用于向百度和google(一个不存在的网站)发起请求,同步的编写写法是先去请求百度或者google,等待请求结束后再请求另一个:123$http = new HTTP();echo $http->get('http://www.baidu.com');echo $http->get('http://www.google.com');基于事件的处理方式可以是这样的:1234567$http = new HTTP();$http->get('www.baidu.com');$http->get('www.huyanping.cn');$http->on('response', function($response){echo $response . PHP_EOL;});$http->run();异步的写法允许我们同时处理多个事务,谁先完成,就先去处理谁。一个简单的异步http客户端见:async-http-phpPHP有很多扩展和包提供了这方面的支持:ext-libevent libevent扩展,基于libevent库,支持异步IO和时间事件ext-event event扩展,支持异步IO和时间事件ext-libev libev扩展,基于libev库,支持异步IO和时间事件ext-eio eio扩展,基于eio库,支持磁盘异步操作ext-swoole swoole扩展,支持异步IO和时间,方便编写异步socket服务器,推荐使用package-react react包,提供了全面的异步编程方式,包括IO、时间事件、磁盘IO等等package-workerman workerman包,类似swoole,php编写发布/订阅:12345$lookup = new nsqphp\Lookup\Nsqlookupd;$nsq = new nsqphp\nsqphp($lookup);$nsq->subscribe('mytopic', 'somechannel', function($msg) {echo $msg->getId() . "\n";})->run();promise:12345678910111213141516171819202122232425function getJsonResult(){return queryApi() ->then( // Transform API results to an object function ($jsonResultString) { return json_decode($jsonResultString); }, // Transform API errors to an exception function ($jsonErrorString) { $object = json_decode($jsonErrorString); throw new ApiErrorException($object->errorMessage); } );}// Here we provide no rejection handler. If the promise returned has been// rejected, the ApiErrorException will be throwngetJsonResult()->done(// Consume transformed object function ($jsonResultObject) { // Do something with $jsonResultObject });promise模式的意义在于解耦,就在刚刚我们提到的异步回调嵌套的问题,可以通过promise解决。其原理是在每一次传递回调函数的过程中,你都会拿到一个promie对象,而这个对象有一个then方法,then方法仍然可以返回一个promise对象,通过传递promise对象可以实现把多层嵌套分离出来。具体的代码需要去研究一下源码才可以,有点难懂,PHP的promise推荐阅读:promise异步的实现原理异步的实现大多情况下少不了循环监听事件,例如我们上面看到$loop->run(),这里其实是一个死循环,监听到事件则调用相应的处理函数。如果你对pcntl熟悉,你一定知道declare(tick=1),其实它也是一种循环,含义是每执行tick行代码,则检查一次是否有尚未处理的信号。虽然会有一个阻塞的死循环(大多数情况下,declare属于特殊情况),但我们可以对多个事件进行监听处理,同时可以在某一个事件处理的过程中停止循环,这样就可以实现并发异步的IO访问,甚至更多。一段伪代码如下:12345678910$async = new Async();$async->on('request', function($requset){do_something_with($request);});// 这里其实就是$loop->run()的核心代码while(true){$async->hasRequest() ? $async->callRequestCallback() : null; sleep(1);}总结整片文章其实并不够详细,充其量算是一篇介绍性的文章,算是我在异步编程方面的一次总结。异步编程的学习并不像学习一门语言或者设计模式那样简单,它要求我们改变传统的编程方式。而异步IO对于学习者要求也略高,首先你必须熟悉同步的IO操作,甚至你需要了解一些协议解析的内容。希望上面的内容对于初学者有一些帮助。文中若有错误的地方,还望指正。
2023年08月10日
14 阅读
0 评论
0 点赞
2023-08-10
PHP 进阶之路 - 亿级 pv 网站架构实战之性能优化
PHP 进阶之路 - 亿级 pv 网站架构实战之性能压榨缘起PV和PU(数据分析—业务指标)PV即访问次数——用户每访问一次可以看作一次PV。PU即访问人数——在同一天内,一个用户无论访问了多少次都算一个访客。通过PV和PU可以分析出用户喜欢产品哪个功能,不喜欢哪个功能,从而根据用户行为来优化产品。为什么过早的优化是万恶之源?在进行优化之前,应该先测试代码的性能,确定是否存在性能问题。同时,也应该优先考虑代码的可读性、可维护性和可扩展性,避免过度优化。使用XHProf查找PHP性能瓶颈XHProf是facebook 开发的一个测试php性能的扩展,本文记录了在PHP应用中使用XHProf对PHP进行性能优化,查找性能瓶颈的方法。性能优化的原则性能优化是建立在对业务的理解之上的性能优化与架构、业务相辅相成、密不可分的性能优化的引入我们先看一张简单的 web 架构图从上到下从用户的浏览器到最后的数据库,那么我们说先前端的优化。前端优化雅虎军规:http://www.cnblogs.com/paul-3... 减少 http 请求数图片、css、script等等这些都会增加http请求数,减少这些元素的数量就能减少响应时间。把多个JS、CSS在可能的情况下写进一个文件,页面里直接写入图片也是不好的做法,应该写进CSS里,小图拼合后利用 background 来定位。现在很多 icon 都是直接做成字体,矢量高清,也减少网络请求数现在的前端框架都会通过组件的方式开发,最后打包生成一个 js 或者 两个 js 文件 + 一个 css 或者两个 css 文件。利用浏览器缓存expires,cache-control,last-modified,etag http://blog.csdn.net/eroswang... 防止缓存,比如资源更新了,原来的做法是?v=xxxx 现在前端的打包工作可以能会生成 /v1.2.0/xxx.js使用分布式存储前端资源接地气利用 cdn 存储前端资源多域名访问资源原因一:浏览器对同一域名的并行请求数有上限,多个域名则支持更多并行请求原因二:使用同一域名的时候无用的 cookie 简直是噩梦数据压缩开启gzip前端资源本身的压缩,js/css 打包编译(去掉空格,语意简化)图片资源的压缩等。优化首屏展示速度资源的按需加载,延时加载 https://blog.csdn.net/m0_64346035/article/details/125131432图片的懒加载,淘宝的商品介绍太多图,用户点击进来又有多少人一直往下看图的呢? 前端懒加载nginx 优化分为下面三个部分来nginx 本身配置的优化worker_processes auto 设置多少子进程worker_cpu_affinity 亲缘性绑定worker_rlimit_nofile 65535 worker 进程打开的文件描述符的最大数worker_connections 65535 子进程最多处理的连接数epoll 多路复用sendfile on 是对文件I/O的系统调用的一个优化,系统api如果是反向代理web服务器,需要配置fastcgi相关的参数数据返回开启gzip压缩静态资源使用 http 缓存协议开启长连接 keepalive_timeout fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 256k; gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.0; gzip_comp_level 2; gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/json; gzip_vary on; gzip_proxied expired no-cache no-store private auth; gzip_disable "MSIE \[1-6\]\\."; location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; }worker_connections和worker_rlimit_nofile有什么区别tcp/ip 网络协议配置的优化/proc/sys/net/ipv4/tcp_tw_recycle 1 开启TCP连接中TIME-WAIT sockets的快速回收,保证tcp_timestamps = 1/proc/sys/net/ipv4/tcp_tw_reuse 1 允许将TIME-WAIT sockets重新用于新的TCP连接/proc/sys/net/ipv4/tcp_syncookies 0 是否需要关闭洪水抵御 看自己业务,比如秒杀,肯定需要关闭了/proc/sys/net/ipv4/tcp_max_tw_buckets 180000 否则经常出现 time wait bucket table overflowtcp_nodelay on 小文件快速返回,我之前通过网络挂载磁盘出现找不到的情况tcp_nopush ontcp_tw_recycle 快速回收可能导致丢包的问题 https://www.im050.com/posts/435linux 系统的优化除了上面的网络协议配置也是在系统基础之外,为了配合nginx自己里面的设定需要做如下修改/proc/sys/net/core/somaxconn 65535ulimit -a 65535Nginx配置性能优化的方法php 优化升级到 php7注意有很多函数和扩展被废弃,比如mysql相关的,有风险,做好测试再切换。opcode 缓存php 5.5 之后好像就内置了吧,需要在php.ini里添加如下配置opcache.revalidate_freq=60 opcache.validate_timestamps=1 opcache.max_accelerated_files=1000 opcache.memory_consumption=512 opcache.interned_strings_buffer=16 opcache.fast_shutdown=1opcache.revalidate_freq这个选项用于设置缓存的过期时间(单位是秒),当这个时间达到后,opcache会检查你的代码是否改变,如果改变了PHP会重新编译它,生成新的opcode,并且更新缓存。opcache.validate_timestamps当这个选项被启用(设置为1),PHP会在opcache.revalidate_freq设置的时间到达后检测文件的时间戳(timestamp)。opcache.max_accelerated_files这个选项用于控制内存中最多可以缓存多少个PHP文件。opcache.memory_consumption你可以通过调用opcachegetstatus()来获取opcache使用的内存的总量opcache.interned_strings_buffer字符串opcache的复用,单位为MBopcache.fast_shutdown=1开启快速停止续发事件,依赖于Zend引擎的内存管理模块php7 hugepage 的使用Hugepage 的作用:间接提高虚拟地址和内存地址转换过程中查表的TLB缓存命中率opcache.huge_code_pages=1鸟哥博客详细介绍:http://www.laruence.com/2015/...代码伪编译以thinkphp为例,它会把框架基础组件(必须用到的组件)合并压缩到一个文件中,不仅减少了文件目录查找,文件打开的系统调用。 通过stracephp-fpm子进程,可以清楚系统调用的过程,在我上面例子中有打开一个文件有12次系统调用(只是举例,我这里相对路径设置的原因导致多了两次文件查找)。如果有10个文件,那就是120次,优化的效果可能不是那么明显,但是这是一种思路。 顺便说下 set_include_path能不用就不要用,上面的demo的截图里面找不到目录就是证明。模板编译模板把它们自定义的语法,最后转换成php语法,这样方便解析。而不是每次都解析一遍。xhprof 查找性能瓶颈xhprof 查找性能瓶颈业务优化非侵入式扩展开发比如原来有一个model,叫问答,现在需要开发一个有奖问答,需要支持话题打赏,里面多了很多功能。这个时候应该利用面向对象的继承的特性。而不是做下面的开发<?php class AskModel { public function detail($id){ $info = 从数据库查询到该问题的信息; // 逻辑1 // 逻辑2 } }<?php class AskModel { public function detail($id){ $info = 从数据库查询到该问题的信息; // 逻辑1 if($info\['type'\] == 2){ //... }else{ } // 逻辑2 if($info\['type'\] == 2){ //... }else{ } } }这样逻辑多了,子类型多了,逻辑判断就非常重复,程序运行起来低效可能是一方面,更多的是不可维护性。业务和架构不分家,架构是建立在对业务的理解之上的。异步思想举例:处理邮件发送。gearman 图片裁剪。页面上 ajax 加载动态数据。图片的懒加载,双击图片看大图。sf 上通过websocket 通知你有新的消息,但是并没有告诉你有什消息,点击消息图标才会去异步请求具体的消息。这些都是异步的思想。能分步走就分步走,能不能请求的就不请求。静态化专题页面,比如秒杀页面,为了应对更大的流量、并发。而且更新起来也比较方便。业务解耦比如刚刚上面说的专题页面,还有必要走整个框架的一套流程吗?进来引用一大堆的文件,初始化一大堆的东西?是不是特别低效呢?所以需要业务解耦,专题页面如果真要框架(可以首次访问之后生成静态页面)也应该是足够轻量级的。不能与传统业务混为一谈。分布式以及 soa说业务优化,真的不得不提架构方面的东西,业务解耦之后,就有了分布式和soa。 说下 soa 自定义 socket 传输协议。 最重要的就是在自定义头里面强调body_len,注意设置为紧凑型,才能保证跨平台性Mysql 优化数据索引相关的文章网上很多了,不足的地方大家补充。表设计 - 拥抱 innodb现在大多数情况都会使用innodb类型了。具体原因是 mysql 专家给的意见。 我自己对 mysql 的优化不了解,每一个细分领域都是一片汪洋,每个人的时间精力是有限的,所以大家也不用什么都非要深入去研究,往往是一些计算机基础更为重要。 参考这份ppt MySQL秘籍.pdf表设计 - 主键索引innodb 需要一个主键,主键不要有业务用途,不要修改主键。主键最好保持顺序递增,随机主键会导致聚簇索引树频繁分裂,随机I/O增多,数据离散,性能下降。举例: 之前项目里有些索引是article_id + tag_id 联合做的主键,那么这种情况下,就是业务了属性了。主键也不是顺序递增,每插入新的数据都有可能导致很大的索引变动(了解下数据库b+索引的原理)表设计 - 字段选择能选短整型,不选长整型。比如一篇文章的状态值,不可能有超过100种吧,不过怎么扩展,没必要用int了。能选 char 就避免 varchar,比如图片资源都有一个hashcode,固定长度20位,那么就可以选char了。当使用 varchar 的时候,长度够用就行,不要滥用。大文本单独分离,比如文章的详情,单独出一张表。其他基本信息放在一张表里,然后关联起来。冗余字段的使用,比如文章的详情字段,增加一个文章markdown解析之后的字段。索引优化大多数情况下,索引扫描要比全表扫描更快,性能更好。但也不是绝对的,比如需要查找的数据占了整个数据表的很大比例,反而使用索引更慢了。没有索引的更新,可能会导致全表数据都被锁住。所以更新的时候要根据索引来做。联合索引的使用explain 的使用联合索引“最左前缀”,查询优化器还会帮你调整条件表达式的顺序,以匹配组合索引的要求。CREATE TABLE `test` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `a` int(10) unsigned NOT NULL, `b` int(10) unsigned NOT NULL, `c` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `index_abc` (`a`,`b`,`c`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;能使用到索引explain select * from test where a=1; explain select * from test where a=1 and b=2; explain select * from test where a=1 and b=2 and c=3; explain select * from test where a=1 and b in (2,3) and c=3; explain select * from test where a=1 and b=2 order by c desc;不能使用索引explain select * from test where a=1 and b in (2,3) order by c desc; explain select * from test where b=2;explain 搜到一篇不错的: http://blog.csdn.net/woshiqjs... 很重要的参数type,key,extratype 最常见的system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALLextra如果有Using filesort或者Using temporary的话,就必须要优化了收集慢查询my.ini 配置里增加long_query_time=2 log-slow-queries=/data/var/mysql_slow.log使用 nosqlredis 丰富的数据类型,非常适合配合mysql 做一些关系型的查询。比如一个非常复杂的查询列表可以将其插入zset 做排序列表,然后具体的信息,通过zset里面的纸去mysql 里面去查询。缓存优化多级缓存请求内缓存static 变量存储,比如朋友圈信息流,在一次性获取20条信息的时候,有可能,点赞的人里面20条里面有30个人是重复的,他们点赞你的a图片也点赞了你的b图片,所以这时,如果能使用static数组来存放这些用户的基本信息就高效了些。本地缓存请求结束了,下拉更新朋友圈,里面又出现了上面的同样的好友,还得重新请求一次。所以本地常驻内存的缓存就更高效了。分布式缓存在A服务器上已经查询过了,在下拉更新的时候被分配到B服务器上了,难道同样的数据再查一次再存到B服务器的本地缓存里面吗,弄一个分布式缓存吧,这样防止了重复查询。但是多了网络请求这一步。很多时候是三者共存的。避免缓存的滥用案例分析用户积分更新比如用户的基本信息和积分混在一起,当用户登录的时候赠送积分。则需要更新用户的积分,这个时候更新整个用户的基本信息缓存么?所以这里也可以运用下面 hashes 分片的原则去更新礼物和主题绑定缓存为了取数据方便把多个数据源混合缓存了,这种情况,相比大家可能都见过,这是灾难性的设计。{id:x,title:x,gift:{ id:x, name:x, img:x, }}如果需要更新礼物的图片,那么所有用到过这个礼物的话题的缓存都要更新。redis 优化多实例化,更高效地利用服务器 cpu内存优化,官方意见 https://redis.io/topics/memor... 有点老尽可能的使用 hashes ,时间复杂度低,查询效率高。同时还节约内存。Instagram 最开始用string来存图片id=>uid的关系数据,用了21g,后来改为水平分割,图片id 1000 取模,然后将分片的数据存在一个hashse 里面,这样最后的内容减少了5g,四分之一基本上。每一段使用一个Hash结构存储,由于Hash结构会在单个Hash元素在不足一定数量时进行压缩存储,所以可以大量节约内存。这一点在String结构里是不存在的。而这个一定数量是由配置文件中的hash-zipmap-max-entries参数来控制的。服务器认知的提升下面的内容,只能是让大家有一个大概的认识,了解一个优化的方向,具体的内容需要系统学习很多很多的知识。多进程的优势多进程有利于 CPU 计算和 I/O 操作的重叠利用。一个进程消耗的绝大部分时间都是在磁盘I/O和网络I/O中。 如果是单进程时cpu大量的时间都在等待I/O,所以我们需要使用多进程。减少上下文切换为了让所有的进程轮流使用系统资源,进程调度器在必要的时候挂起正在运行的进程,同时恢复以前挂起的某个进程。这个就是我们常说的“上下文切换”。无限制增加进程数,则会增多 cpu 在各个进程间切换的次数。 如果我们希望服务器支持较大的并发数,那么久要尽量减少上下文切换的次数,比如在nginx服务上nginx的子进程数不要超过cpu的核数。 我们可以在压测的时候通过vmstat,nmon来监控系统上下文切换的次数。IOwait 不一定是 I/O 繁忙# top top - 09:40:40 up 565 days, 5:47, 2 users, load average: 0.03, 0.03, 0.00 Tasks: 121 total, 2 running, 119 sleeping, 0 stopped, 0 zombie Cpu(s): 8.6%us, 0.3%sy, 0.0%ni, 90.7%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st一般情况下IOwait代表I/O操作的时间占(I/O操作的时间 + I/O和CPU时间)的比例。 但是也时候也不准,比如nginx来作为web服务器,当我们开启很多nginx子进程,IOwait会很高,当再减少进程数到cpu核数附近时,IOwait会减少,监控网络流量会发现也增加。多路复用 I/O 的使用只要是提供socket服务,就可以利用多路复用 I/O 模型。减少系统调用strace 非常方便统计系统调用# strace -c -p 23374Process 23374 attached - interrupt to quit ^CProcess 23374 detached % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 30.68 0.000166 0 648 poll 12.01 0.000065 0 228 munmap 11.65 0.000063 0 228 mmap 10.54 0.000057 0 660 recvfrom 10.35 0.000056 0 708 fstat 7.76 0.000042 0 252 open 6.10 0.000033 1 36 write 5.73 0.000031 0 72 24 access 5.18 0.000028 0 72 read 0.00 0.000000 0 276 close 0.00 0.000000 0 13 13 stat 0.00 0.000000 0 269 240 lstat 0.00 0.000000 0 12 rt_sigaction 0.00 0.000000 0 12 rt_sigprocmask 0.00 0.000000 0 12 pwrite 0.00 0.000000 0 48 setitimer 0.00 0.000000 0 12 socket 0.00 0.000000 0 12 connect 0.00 0.000000 0 12 accept 0.00 0.000000 0 168 sendto 0.00 0.000000 0 12 shutdown 0.00 0.000000 0 48 fcntl 0.00 0.000000 0 12 flock 0.00 0.000000 0 156 getcwd 0.00 0.000000 0 24 chdir 0.00 0.000000 0 24 times 0.00 0.000000 0 12 getuid ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000541 4038 277 total通过strace查看“系统调用时间”和“调用次数”来定位问题strace:跟踪进程的系统调用 、ltrace:跟踪进程调用库函数自己构建web服务器要想理解web服务器优化的原理,最好的办法是了解它的来龙去脉,实践就是最好的方式,我分为以下几个步骤:用 PHP 来实现一个动态 Web 服务器 简单静态 web 服务器(循环服务器)的实现 多进程并发的面向连接 Web 服务器的实践简单静态 Select Web 服务器的实现I/O 多路复用上面是我的学习笔记,图片资源丢失了,大家可以根据相关关键词去搜搜相关的文章和书籍,更推荐大家去看书。
2023年08月10日
26 阅读
0 评论
0 点赞
2023-08-10
php实现协程,真正的异步
php实现协程,真正的异步github上php的协程大部分是根据这篇文章实现的:http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html。它们最终的结果都是把回调变成了优雅的顺序执行的代码,但还是阻塞的,不是真正的异步。比如最热门的:https://github.com/recoilphp/recoil先安装:composer require recoil/recoil:执行:<?php //recoil.php include __DIR__ . '/vendor/autoload.php'; use Recoil\React\ReactKernel; $i = 100000; ReactKernel::start(task1()); ReactKernel::start(task2()); function task1(){ global $i; echo "wait start" . PHP_EOL; while ($i-- > 0) { yield; } echo "wait end" . PHP_EOL; }; function task2(){ echo "Hello " . PHP_EOL; yield; echo "world!" . PHP_EOL; }结果:wait start//等待若干秒wait endHelloworld!我本来是想让两个任务并行,结果两个任务变成了串行,中间等待的时间什么事情都干不了。React响应式的编程是严格禁止这种等待的,所以我就参照unity3d的协程自己写了个php版本的。上代码:<?php //Coroutine.php //依赖swoole实现的定时器,也可以用其它方法实现定时器 class Coroutine { //可以根据需要更改定时器间隔,单位ms const TICK_INTERVAL = 1; private $routineList; private $tickId = -1; public function __construct() { $this->routineList = []; } public function start(Generator $routine) { $task = new Task($routine); $this->routineList[] = $task; $this->startTick(); } public function stop(Generator $routine) { foreach ($this->routineList as $k => $task) { if($task->getRoutine() == $routine){ unset($this->routineList[$k]); } } } private function startTick() { swoole_timer_tick(self::TICK_INTERVAL, function($timerId){ $this->tickId = $timerId; $this->run(); }); } private function stopTick() { if($this->tickId >= 0) { swoole_timer_clear($this->tickId); } } private function run() { if(empty($this->routineList)){ $this->stopTick(); return; } foreach ($this->routineList as $k => $task) { $task->run(); if($task->isFinished()){ unset($this->routineList[$k]); } } } } class Task { protected $stack; protected $routine; public function __construct(Generator $routine) { $this->routine = $routine; $this->stack = new SplStack(); } /** * [run 协程调度] * @return [type] [description] */ public function run() { $routine = &$this->routine; try { if(!$routine){ return; } $value = $routine->current(); //嵌套的协程 if ($value instanceof Generator) { $this->stack->push($routine); $routine = $value; return; } //嵌套的协程返回 if(!$routine->valid() && !$this->stack->isEmpty()) { $routine = $this->stack->pop(); } $routine->next(); } catch (Exception $e) { if ($this->stack->isEmpty()) { /* throw the exception */ return; } } } /** * [isFinished 判断该task是否完成] * @return boolean [description] */ public function isFinished() { return $this->stack->isEmpty() && !$this->routine->valid(); } public function getRoutine() { return $this->routine; } }测试代码:<?php //test.php require 'Coroutine.php'; $i = 10000; $c = new Coroutine(); $c->start(task1()); $c->start(task2()); function task1(){ global $i; echo "wait start" . PHP_EOL; while ($i-- > 0) { yield; } echo "wait end" . PHP_EOL; }; function task2(){ echo "Hello " . PHP_EOL; yield; echo "world!" . PHP_EOL; }结果:wait startHelloworld!//等待几秒,但不阻塞wait end注:此文章需要验证。
2023年08月10日
10 阅读
0 评论
0 点赞
1
2