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基础
页面
关于
搜索到
26
篇与
的结果
2023-12-15
MySQL 的索引是什么?怎么优化?
MySQL 的索引是什么?怎么优化?索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本。MySQL在300万条记录左右性能开始逐渐下降,虽然官方文档说500~800w记录,所以大数据量建立索引是非常有必要的。MySQL提供了Explain,用于显示SQL执行的详细信息,可以进行索引的优化。一、导致SQL执行慢的原因1.硬件问题。如网络速度慢,内存不足,I/O吞吐量小,磁盘空间满了等。2.没有索引或者索引失效。(一般在互联网公司,DBA会在半夜把表锁了,重新建立一遍索引,因为当你删除某个数据的时候,索引的树结构就不完整了。所以互联网公司的数据做的是假删除.一是为了做数据分析,二是为了不破坏索引 )3.数据过多(分库分表)4.服务器调优及各个参数设置(调整my.cnf)二、分析原因时,一定要找切入点1.先观察,开启慢查询日志,设置相应的阈值(比如超过3秒就是慢SQL),在生产环境跑上个一天过后,看看哪些SQL比较慢。2.Explain和慢SQL分析。比如SQL语句写的烂,索引没有或失效,关联查询太多(有时候是设计缺陷或者不得以的需求)等等。3.Show Profile是比Explain更近一步的执行细节,可以查询到执行每一个SQL都干了什么事,这些事分别花了多少秒。4.找DBA或者运维对MySQL进行服务器的参数调优。三、什么是索引?MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。我们可以简单理解为:快速查找排好序的一种数据结构。Mysql索引主要有两种结构:B+Tree索引和Hash索引。我们平常所说的索引,如果没有特别指明,一般都是指B树结构组织的索引(B+Tree索引)。索引如图所示:最外层浅蓝色磁盘块1里有数据17、35(深蓝色)和指针P1、P2、P3(黄色)。P1指针表示小于17的磁盘块,P2是在17-35之间,P3指向大于35的磁盘块。真实数据存在于子叶节点也就是最底下的一层3、5、9、10、13……非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如17、35。查找过程:例如搜索28数据项,首先加载磁盘块1到内存中,发生一次I/O,用二分查找确定在P2指针。接着发现28在26和30之间,通过P2指针的地址加载磁盘块3到内存,发生第二次I/O。用同样的方式找到磁盘块8,发生第三次I/O。真实的情况是,上面3层的B+Tree可以表示上百万的数据,上百万的数据只发生了三次I/O而不是上百万次I/O,时间提升是巨大的。四、Explain 分析前文铺垫完成,进入实操部分,先来插入测试需要的数据:CREATE TABLEuser_info(idBIGINT(20)NOTNULLAUTO_INCREMENT,nameVARCHAR(50)NOTNULLDEFAULT'',ageINT(11)DEFAULTNULL,PRIMARY KEY(id),KEYname_index(name))ENGINE = InnoDB DEFAULTCHARSET = utf8;INSERT INTO user_info(name,age)VALUES('xys',20);INSERT INTO user_info(name,age)VALUES('a',21);INSERT INTO user_info(name,age)VALUES('b',23);INSERT INTO user_info(name,age)VALUES('c',50);INSERT INTO user_info(name,age)VALUES('d',15);INSERT INTO user_info(name,age)VALUES('e',20);INSERT INTO user_info(name,age)VALUES('f',21);INSERT INTO user_info(name,age)VALUES('g',23);INSERT INTO user_info(name,age)VALUES('h',50);INSERT INTO user_info(name,age)VALUES('i',15);CREATE TABLEorder_info(idBIGINT(20)NOTNULLAUTO_INCREMENT,user_idBIGINT(20)DEFAULTNULL,product_nameVARCHAR(50)NOTNULLDEFAULT'',productorVARCHAR(30)DEFAULTNULL,PRIMARY KEY(id),KEYuser\_product\_detail_index(user_id,product_name,productor))ENGINE = InnoDB DEFAULTCHARSET = utf8;INSERT INTO order_info(user_id,product_name,productor)VALUES(1,'p1','WHH');INSERT INTO order_info(user_id,product_name,productor)VALUES(1,'p2','WL');INSERT INTO order_info(user_id,product_name,productor)VALUES(1,'p1','DX');INSERT INTO order_info(user_id,product_name,productor)VALUES(2,'p1','WHH');INSERT INTO order_info(user_id,product_name,productor)VALUES(2,'p5','WL');INSERT INTO order_info(user_id,product_name,productor)VALUES(3,'p3','MA');INSERT INTO order_info(user_id,product_name,productor)VALUES(4,'p1','WHH');INSERT INTO order_info(user_id,product_name,productor)VALUES(6,'p1','WHH');INSERT INTO order_info(user_id,product_name,productor)VALUES(9,'p8','TE');初体验,执行Explain的效果:索引使用情况在possible\_keys、key和key\_len三列,接下来我们先从左到右依次讲解。1.id--id相同,执行顺序由上而下explain selectu.,o. from user_infou,order_infoowhereu.id=o.user_id;--id不同,值越大越先被执行explain select *from user_info where id=(select user\_id from order\_info where product_name ='p8');2.select_type可以看id的执行实例,总共有以下几种类型:SIMPLE: 表示此查询不包含 UNION 查询或子查询PRIMARY: 表示此查询是最外层的查询SUBQUERY: 子查询中的第一个 SELECTUNION: 表示此查询是 UNION 的第二或随后的查询DEPENDENT UNION: UNION 中的第二个或后面的查询语句, 取决于外面的查询UNION RESULT, UNION 的结果DEPENDENT SUBQUERY: 子查询中的第一个 SELECT, 取决于外面的查询. 即子查询依赖于外层查询的结果.DERIVED:衍生,表示导出表的SELECT(FROM子句的子查询)3.tabletable表示查询涉及的表或衍生的表:explain select tt. from (select u. from user\_info u,order\_info o where u.id=o.user_id and u.id=1) ttid为1的的表示id为2的u和o表衍生出来的。4.typetype 字段比较重要,它提供了判断查询是否高效的重要依据依据。 通过 type 字段,我们判断此次查询是 全表扫描 还是 索引扫描等。 type 常用的取值有:system: 表中只有一条数据, 这个类型是特殊的 const 类型。const: 针对主键或唯一索引的等值查询扫描,最多只返回一行数据。 const 查询速度非常快, 因为它仅仅读取一次即可。例如下面的这个查询,它使用了主键索引,因此 type 就是 const 类型的:explain select * from user_info where id = 2;eq\_ref: 此类型通常出现在多表的 join 查询,表示对于前表的每一个结果,都只能匹配到后表的一行结果。并且查询的比较操作通常是 =,查询效率较高。例如:explain select * from user\_info, order\_info where user\_info.id = order\_info.user\_id;ref: 此类型通常出现在多表的 join 查询,针对于非唯一或非主键索引,或者是使用了 最左前缀 规则索引的查询。例如下面这个例子中, 就使用到了 ref 类型的查询:explain select * from user\_info, order\_info where user\_info.id = order\_info.user\_id AND order\_info.user_id = 5range: 表示使用索引范围查询,通过索引字段范围获取表中部分数据记录。这个类型通常出现在 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中。例如下面的例子就是一个范围查询:explain select * from user_info where id between 2 and 8;index: 表示全索引扫描(full index scan),和 ALL 类型类似,只不过 ALL 类型是全表扫描,而 index 类型则仅仅扫描所有的索引, 而不扫描数据。index 类型通常出现在:所要查询的数据直接在索引树中就可以获取到, 而不需要扫描数据。当是这种情况时,Extra 字段 会显示 Using index。ALL: 表示全表扫描,这个类型的查询是性能最差的查询之一。通常来说, 我们的查询不应该出现 ALL 类型的查询,因为这样的查询在数据量大的情况下,对数据库的性能是巨大的灾难。 如一个查询是 ALL 类型查询, 那么一般来说可以对相应的字段添加索引来避免。通常来说, 不同的 type 类型的性能关系如下:ALL < index < range ~ index\_merge < ref < eq\_ref < const < system ALL 类型因为是全表扫描, 因此在相同的查询条件下,它是速度最慢的。而 index 类型的查询虽然不是全表扫描,但是它扫描了所有的索引,因此比 ALL 类型的稍快.后面的几种类型都是利用了索引来查询数据,因此可以过滤部分或大部分数据,因此查询效率就比较高了。5.possible_keys它表示 mysql 在查询时,可能使用到的索引。 注意,即使有些索引在 possible_keys 中出现,但是并不表示此索引会真正地被 mysql 使用到。 mysql 在查询时具体使用了哪些索引,由 key 字段决定。6.key此字段是 mysql 在当前查询时所真正使用到的索引。比如请客吃饭,possible_keys是应到多少人,key是实到多少人。当我们没有建立索引时:explain selecto.* from order_infoowhereo.product_name= 'p1'ando.productor='whh';create index idx\_name\_productor on order_info(productor);drop index idx\_name\_productor on order_info;建立复合索引后再查询:7.key_len表示查询优化器使用了索引的字节数,这个字段可以评估组合索引是否完全被使用。8.ref这个表示显示索引的哪一列被使用了,如果可能的话,是一个常量。前文的type属性里也有ref,注意区别。9.rowsrows 也是一个重要的字段,mysql 查询优化器根据统计信息,估算 sql 要查找到结果集需要扫描读取的数据行数,这个值非常直观的显示 sql 效率好坏, 原则上 rows 越少越好。可以对比key中的例子,一个没建立索引钱,rows是9,建立索引后,rows是4。10.extraexplain 中的很多额外的信息会在 extra 字段显示, 常见的有以下几种内容:using filesort :表示 mysql 需额外的排序操作,不能通过索引顺序达到排序效果。一般有 using filesort都建议优化去掉,因为这样的查询 cpu 资源消耗大。using index:覆盖索引扫描,表示查询在索引树中就可查找所需数据,不用扫描表数据文件,往往说明性能不错。using temporary:查询有使用临时表, 一般出现于排序, 分组和多表 join 的情况, 查询效率不高,建议优化。using where :表名使用了where过滤。五、优化案例explain select u.,o. from user\_info u LEFT JOIN order\_info o on u.id=o.user_id;执行结果,type有ALL,并且没有索引:开始优化,在关联列上创建索引,明显看到type列的ALL变成ref,并且用到了索引,rows也从扫描9行变成了1行:这里面一般有个规律是:左链接索引加在右表上面,右链接索引加在左表上面。六、是否需要创建索引?索引虽然能非常高效的提高查询速度,同时却会降低更新表的速度。实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的。我是个普通的程序猿,水平有限,文章难免有错误,欢迎牺牲自己宝贵时间的读者,就本文内容直抒己见,我的目的仅仅是希望对读者有所帮助。来源:我叫刘半仙 my.oschina.net/liughDevelop/blog/1788148
2023年12月15日
11 阅读
0 评论
0 点赞
2023-11-21
strace:跟踪进程的系统调用 、ltrace:跟踪进程调用库函数
strace:跟踪进程的系统调用 、ltrace:跟踪进程调用库函数strace:跟踪进程的系统调用是 Linux 环境下的一款 程序调试工具 , 用于检查一个应用程序所使用的系统调用以及它所接收的系统信息 。strace会追踪程序运行时的整个生命周期,输出每一个系统调用的名字、参数、返回值和执行所消耗的时间等,是高级运维和开发人员排查问题的杀手铜。 strace命令的参数选项及说明-c 统计每一个系统调用所执行的时间、次数和出错的次数等 -d 输出strace关于标准错误的调试信息 -f 跟踪目标进程,以及目标进程创建的所有子进程 -ff 如果提供-o filename,则将所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号 -i 输出系统调用的入口指针 -q 禁止输出关于脱离的消息 -r 输出每一个系统调用的相对时间 -t 在输出中的每一行前加上时间信息。例如16:45:28 -tt 在输出中的每一行前加上时间信息,精确到微秒。例如11:18:59.759546端 -ttt 在输出中的每一行前加上时间信息,精确到微秒,而且时间表示为UNIX时间戳。例如1486111461.650434 -T 显示每次系统调用所花费的时间 -v 对于某些相关调用,把完整的环境变量、文件stat结构等打印出来 -x 以十六进制形式输出非标准字符率 -xx 所有字符串以十六进制形式输出 -e expr 输出过滤器,通过表达式,可以过滤掉你不想要的输出 expr是一个表达式,用于控制如何跟踪:[qualifier=][!][valuel[,value2].. 说明: ①qualifier 只能是trace、abbrev、verbose、raw、signal、read、write其中之一 ②value是用来限定的符号或数字 ③默认的qualifier是trace ④感叹号是否定符号 例如: -e open等价于-e trace=open,表示只跟踪open调用 而-e trace!=open表示跟踪除了open以外的其他调用 常见选项: -e trace=[set] 只跟踪指定的系统调用 -e trace=file 只跟踪与文件操作有关的系统调用 -e trace=process 只跟踪与进程控制有关的系统调用 -e trace-network 只跟踪与网络有关的系统调用 -e trace=signal 只跟踪与系统信号有关的系统调用 -e trace=desc 只跟踪与文件描述符有关的系统调用 -e trace=ipc 只跟踪与进程通信有关的系统调用 -e abbrev=[set] 设定strace输出的系统调用的结果集 -e raw=[set] 将指定的系统调用的参数以十六进制显示 -e signal=[set] 指定跟踪的系统信号 -e read=[set] 输出从指定文件中读出的数据 -e write=[set] 输出写入到指定文件中的数据 -o filename 将strace的输出写入文件filename -p pid 指定要跟踪的进程pid,要同时跟踪多个pid,重复多次p选项即可* -s strsize 指定输出的字符串的最大长度,默认为32。并没有将文件名视为字符串,默认全部输出 -u username 以usemame的UID和GID执行所跟踪的命令 排查Nginx403 forbidden错误strace -tt -f /applicatton/nginx/sbin/nginx只跟踪与文件操作有关的系统调用 strace -tt -f -e trace=file /application/nginx/sbin/nginx #只跟综与文件操作有关的系统调用。通过pid 跟踪进程pgrep nginx[root@bzhl ~]# pgrep nginx 1884 7785 7786 7787pstree -p 1884(端口号)[root@bzhl ~]# pstree -p 1884 nginx(1884)─┬─nginx(7785) ├─nginx(7786) └─nginx(7787)strace -tt -f -e trace=file -p 7785(端口号)[root@bzhl ~]# strace -tt -f -e trace=file -p 7785 strace: Process 7785 attached 跟踪系统调用统计 strace不仅能够追踪系统调用,使用选项-c还能对进程所有的系统调用做一个统计分析。 [root@bzhl ~]# which nginx /usr/bin/nginx [root@bzhl ~]# strace -c /usr/bin/nginx % time seconds usecs/call calls errors syscall \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 22.33 0.001129 7 153 52 open 15.55 0.000786 6 123 close 10.80 0.000546 6 95 mmap 8.53 0.000431 13 32 write 7.66 0.000387 10 39 read 6.47 0.000327 7 48 mprotect 5.38 0.000272 12 22 munmap 4.35 0.000220 3 87 fstat 3.20 0.000162 32 5 nanosleep 2.87 0.000145 8 19 socket 2.67 0.000135 4 38 pread64 2.29 0.000116 29 4 4 connect 1.19 0.000060 4 15 15 bind 1.03 0.000052 3 16 5 stat 1.03 0.000052 9 6 getdents 0.99 0.000050 3 15 setsockopt 0.65 0.000033 11 3 openat 0.63 0.000032 2 15 ioctl 0.63 0.000032 5 6 6 mkdir 0.47 0.000024 2 12 fcntl 0.16 0.000008 8 1 statfs 0.14 0.000007 7 1 1 readlink 0.10 0.000005 5 1 epoll_create 0.08 0.000004 2 2 rt_sigaction 0.08 0.000004 2 2 uname 0.08 0.000004 2 2 gettimeofday 0.08 0.000004 4 1 futex 0.06 0.000003 3 1 poll 0.06 0.000003 3 1 lseek 0.06 0.000003 2 2 getrlimit 0.06 0.000003 3 1 getppid 0.06 0.000003 3 1 sched_getaffinity 0.04 0.000002 1 2 brk 0.04 0.000002 2 1 rt_sigprocmask 0.04 0.000002 2 1 getuid 0.04 0.000002 2 1 arch_prctl 0.04 0.000002 2 1 set\_tid\_address 0.04 0.000002 2 1 set\_robust\_list 0.02 0.000001 1 1 geteuid 0.00 0.000000 0 1 1 access 0.00 0.000000 0 1 execve \-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 100.00 0.005055 779 84 total 上面的结果将清楚地告诉我们调用了哪些系统函数,调用的次数是多少,消耗了多少时间等信息,这对我们分析程序来说是非常有用的。 重定向输出 strace -c -o tongji.log /application/nginx/sbin/nginx #用 -o 选项将strace的结果输出到文件中 对系统调用进行计时 strace -T /application/nginx/sbin/ngirnx #<=使用选项-T将每个系统调用所花费的时间打印出来,每个调用的时间花费在调用行最右边的尖括导里面。 小结:strace命令很适合处埋程序僵尸、命令执行报错等问题,如果从程序日志和系统日志中看不出问题出现的原因,则可以strace一下,也许会有答案,不过也需要使用者有足够的耐心去查看输出! ltrace:跟踪进程调用库函数ltrace 能够跟踪进程的库函数调用 ,它会显现出调用了哪个库函数,而 strace则是跟踪进程的每个系统调用 。 ltrace命令的参数选项及说明-c 统计库函数每次调用的时间,最后程序退出时打印摘要 -C 解码低级别名称(内核级)为用户级名称 -d 打印调试信息 -e expr 输出过滤器,通过表达式,可以过滤掉你不想要的输出 -e printf 表示只查看printf函数调用 -e !printf 表示查看除printf函数以外的所有函数调用 -f 跟踪子进程 -o filename 将ltrace的输出写入文件filename -p pid 指定要跟踪的进程pid -r 输出每一个调用的相对时间 -S 显示系统调用 -t 在输出中的每一行前加上时间信息。例如16:45:28 -tt 在输出中的每一行前加上时间信息,精确到微秒。例如11:18:59.759546 -ttt 在输出中的每一行前加上时间信息,精确到微秒,而且时间表示为UNIX时间截。例如1486111461.650434 -T 显示每次调用所花费的时间 -u username 以username的UID和GID执行所跟踪的命令 Itrace使用ltrace的用法与strace非常相似,选项功能也是类似[root@bzhl ~]# ltrace /usr/bin/nginx # 提示: -bash: ltrace: command not found # 则:yum -y install ltrace #通过pid 跟踪进程调用库函数。 [root@bzhl ~]# pgrep nginx 1884 7785 7786 7787 [root@bzhl ~]# ltrace -p 1884
2023年11月21日
17 阅读
0 评论
0 点赞
2023-11-21
前端懒加载
前端懒加载一、什么是懒加载?什么预加载?概念:懒加载 也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。 有的网站图片很多,而如果一上来就加载所有的图片,会导致网页加载很慢; 图片懒加载:等图片正式进入到可视区中时,才加载对应的图片,否则不请求图片预加载 指的是将所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。通过预加载能够减少用户的等待时间,提高用户的体验。我了解的预加载的最常用的方式是使用 js 中的 image 对象,通过为 image 对象来设置 scr 属性,来实现图片的预加载。懒加载和预加载的区别区别:两者的行为是相反的,预加载是提前加载,懒加载是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。意义:懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。预加载:预加载可以说是牺牲服务器前端性能,换取更好的用户体验,这样可以使用户的操作得到最快的反映。网站正常加载和预加载预加载则是指在用户访问网站之前,网站会提前加载一些可能会用到的文件,以提高用户体验和页面加载速度。这些文件可能是网站的核心资源,或者是用户可能会访问的页面的文件,例如首页的图片、CSS 文件等。预加载可以通过一些技术手段来实现,比如使用预加载标签 预加载资源。网站正常加载是按需加载,而预加载则是提前加载可能会用到的文件,以提高用户体验。二、图片懒加载的基本实现图片的加载是由src引起的,当对src赋值时,浏览器就会请求图片资源。根据这个原理,我们使用HTML5的data-xxx属性来储存图片的路径,在需要加载图片的时候,将data-xxx中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。注意:data-xxx中的xxx可以自定义,这里我们使用data-src来定义。懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。<div class="container"> <img src="loading.gif" data-src="pic.png"> <img src="loading.gif" data-src="pic.png"> <img src="loading.gif" data-src="pic.png"> <img src="loading.gif" data-src="pic.png"> <img src="loading.gif" data-src="pic.png"> <img src="loading.gif" data-src="pic.png"> </div> <script> var imgs = document.querySelectorAll('img'); function lozyLoad(){ var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; var winHeight= window.innerHeight; for(var i=0;i < imgs.length;i++){ if(imgs[i].offsetTop < scrollTop + winHeight ){ imgs[i].src = imgs[i].getAttribute('data-src'); } } } window.onscroll = lozyLoad(); </script> 三、Intersection Observer实现图片懒加载Intersection Observer是HTML5新增的API,可以用来实现图片懒加载。MDN中对Intersection Observer的解释IntersectionObserver接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)当一个IntersectionObserver对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦IntersectionObserver被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。这里封装一个组件并且自定义一个v-lazy属性,然后替换到src上,实现懒加载。import { useIntersectionObserver } from "@vueuse/core"; import defaultImg from '@/assets/images/200.png' import { App } from 'vue'; export default { install(app: App) { // 全局指令 app.directive('lazy', { // mounted 是 v3 中自定义指令的生命周期,他会被自动调用 // 它表示的含义和组件的mounted是一样的 // el是 dom 元素, binding mounted(el, binding) { el.src = defaultImg console.log('lazy', el, binding.value); //实时鉴定el是否可见, 如果可见 给它的src设置binding.value const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => { if (isIntersecting) { el.src = binding.value stop() el.onerror = function () { el.src = defaultImg } } }) } }) } } <img v-lazy="item.picture" alt=""/>四. 延迟加载视频图片和视频这类静态资源资源占比都最大。与图片一样,视频同样可以延迟加载,来达到优化性能的目的。正常情况下加载视频,使用的是 video 标签,那么对于一些需要由用户自己播放的视频,最好指定video标签的preload属性为none,这样浏览器就不会预加载任何视频数据。为了占用空间,使用poster属性为video占位。如下:<video controls preload="none" poster="replace.jpg"> <source src="main.webm" type="video/webm"> <source src="main.mp4" type="video/mp4"> </video>五. 使用第三方延迟加载库除了上面介绍的一些延迟加载方法之外,还可以借助一些已经封装好的第三方库,下面是一些成熟的第三方库: lozad.js 是超轻量级且只使用 Intersection Observer 的库, 因此它的性能极佳,但如果要在旧版本浏览器上使用,则需要配置polyfill。 lazysizes 是功能全面的延迟加载库,其使用的模式与本文所示的代码示例非常相似,会自动与元素上的lazyload 类绑定,然后在data-src 和/或 data-srcset 属性中指定图像网址,该库还可以通过许多插件进行扩展,执行延迟各种资源等操作。 如果使用React,可以使用 react-lazyload来进行图片懒加载操作,这个库是React图片懒加载的主流解决方案。
2023年11月21日
34 阅读
0 评论
0 点赞
2023-08-12
使用PHP做 http pxory 缓存&代理, 使用redis做缓存,支持毫秒过期,拥有超高性能
使用PHP做 http pxory 缓存&代理, 使用redis做缓存,支持毫秒过期,拥有超高性能<?php //PHP http pxory 缓存&代理, 使用redis做缓存,支持毫秒过期,拥有超高性能 $url=@$_GET['url']; if (empty($_GET['url'])) { echo 'url is empty '; exit; } $path=parse_url($url, PHP_URL_PATH); $key=$path; $redis = new Redis(); $redis->pconnect('127.0.0.1', 6379); if ($content=$redis->get($key)) { echo $content; exit; } // Client $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_NOSIGNAL, 1); //注意,毫秒超时一定要设置这个 curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500); //超时毫秒,cURL 7.16.2中被加入。从PHP 5.2.3起可使用 $data = curl_exec($ch); $curl_errno = curl_errno($ch); $curl_error = curl_error($ch); curl_close($ch); if ($curl_errno > 0) { echo "cURL Error ($curl_errno): $curl_error\n"; } else { // $redis->setEx('key', 3600, 'value');//以秒为单位 $redis->pSetEx($key, 50000, $data); // 将参数中的字符串值设置为键的值,并带有生存时间 pSetEx以毫秒为单位. echo $data; exit; }使用方法:http://localhost/proxy.php?url=https://www.xxxxxxx.com:3004/rooms/5f392ac745f6cd207b5301db经压力测试,性能超高.!!
2023年08月12日
12 阅读
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 点赞
1
...
3
4
5
6