Cgi、FastCgi 与 PHP-FPM

CGI 的作用

web server(比如说 nginx)只是内容的分发者。

  • 如果请求 /index.html,那么 web server 会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。
  • 如果现在请求的是 /index.php,根据配置文件,nginx 知道这个不是静态文件,需要去找 PHP 解析器来处理,那么他会把这个请求简单处理后交给 PHP 解析器。Nginx 会传哪些数据给 PHP 解析器呢?url、查询字符串、POST 数据、HTTP header等等,CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。

当 web server 收到 /index.php 这个请求后,会启动对应的 CGI 程序,这里就是 PHP 的解析器。接下来 PHP 解析器会解析 php.ini 文件,初始化执行环境,然后处理请求,再以规定 CGI 规定的格式返回处理后的结果,退出进程。web server 再把结果返回给浏览器。

fastCgi 是什么

fastCgi 是用来提高 CGI 程序性能的。

那么 CGI 程序的性能问题在哪呢?”PHP 解析器会解析 php.ini 文件,初始化执行环境”,就是这里了。标准的 CGI 对每个请求都会执行这些步骤,所以处理每个请求的时间会比较长。

那么 fastCgi 是怎么做的呢?首先,fastCgi 会先启一个 master,解析配置文件,初始化执行环境,然后再启动多个 worker。当请求过来时,master 会传递给一个 worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。而且当 worker 不够用时,master 可以根据配置预先启动几个 worker 等着;当然空闲 worker 太多时,也会停掉一些,这样就提高了性能,也节约了资源。这就是 fastCgi 对进程的管理。

PHP-FPM 是什么

PHP-FPM 是一个实现了 FastCgi 的程序,被 PHP 官方收录。

mysql知识

MySQL存储引擎 MyISAM 和 InnoDB 的区别

  • MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.
  • InnoDB不支持FULLTEXT类型的索引.
  • InnoDB中不保存表的具体行数,但是MyISAM只要简单的读出保存好的行数即可.
  • MyISAM支持表锁,只有读读之间是并发的,写写之间和读写之间(读和插入之间是可以并发的,去设置concurrent_insert参数,定期执行表优化操作,更新操作就没有办法了)是串行的,所以写起来慢;InnoDB支持行锁,这个一般指的是sql用到索引的时候,行锁是加在索引上的,不是加在数据记录上的,如果sql没有用到索引,仍然会锁定表,普通的select是不需要锁的
  • MyISAM索引btree上的节点是一个指向数据物理位置的指针,所以查找起来很快;nnodb索引节点存的则是数据的主键,所以需要根据主键二次查找
  • 因为在使用索引的时候用的是行锁,锁的粒度小,竞争相同锁的情况就少,就增加了并发处理,所以并发读写的效率还是很优秀的,问题在于索引查询后的根据主键的二次查找导致效率低

数据库设计范式

第一范式:每个属性都不可再分解
第二范式:每个属性都依赖与主键
第三范式:除了主键外,其他属性都没有依赖关系

MYSQL 性能优化

  • 选择合适的存储引擎,设计良好的数据库结构,选择合适的表字段数据类型,允许部分数据冗余(空间换时间)
  • 适当的添加索引
  • 优化 sql 语句,不同的语句,根据你选择的引擎、表中数据的分布情况、索引情况、数据库优化策略、查询中的锁策略等因素,最终查询的效率相差很大;优化要从整体去考虑,有时你优化一条语句后,其它查询反而效率被降低了,所以要取一个平衡点
  • Cache(缓存数据)
    查询:查询之前,要在Memcached或Redis中查找结果,如果找到,则返回它;如果未找到,则到数据库服务器上执行查询,并将结果返回给Memcached或Redis
    插入:先把数据插入数据库,在内存中受此影响的数据库将变成无效
  • 读写分离
  • 分布数据(分割数据)找规律分表,减少单表中的数据量提高查询速度

关于缓存

  • 一般的首页不应当有查询,对首页生成静态页面
  • 不经常改动的页面,生成静态页面.

切分

  • 垂直切分保证业务的独立性,防止不同业务争抢资源,毕竟业务是有优先级的
  • 切分后也可对不同片数据进行不同优化。如按时间切分,超过一定时间数据不允许修改,就可以引入压缩了,数据传输及读取减少很多
  • 数据是否存在明显的冷热(考虑旧数据归档)

关于高并发的处理

用同步队列,就可以实现。库存比如是1000,那就存1000个随机数到队列中,拿到随机数的人去换取真实的商品。这样数据库的压力都小。最多更新1000次。队列可以系统加载时创建,也可以做为持久化保存在文件中。

关于库存和秒杀的解决方案

  1. 用额外的单进程处理一个队列,下单请求放到队列里,一个个处理,就不会有并发的问题了,但是要额外的后台进程以及延迟问题,不予考虑。
  2. 根据update结果来判断,我们可以加一个判断条件update … where 库存>0,如果返回false,则说明库存不足,并回滚事务。
  3. 借助文件排他锁,在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户”服务器繁忙”
1
2
3
4
5
6
7
8
9
//阻塞(等待)模式
$fp = fopen("lock.txt", "w+");
if(flock($fp,LOCK_EX))
{
//..处理订单
flock($fp,LOCK_UN);
}
fclose($fp);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//非阻塞模式
$fp = fopen("lock.txt", "w+");
if(flock($fp,LOCK_EX | LOCK_NB))
{
//..处理订单
flock($fp,LOCK_UN);
}
else
{
echo "系统繁忙,请稍后再试";
}
fclose($fp);
//采用哪种方式,看并发数量吧。

docker 技巧

删除 none tag 镜像

1
docker rmi $(docker images | grep "^<none>" | awk '{print $3}')
1
docker rmi $(docker images -q --filter "dangling=true")

删除所有镜像

1
docker images -q | xargs docker rmi

删除所有容器

1
docker ps -q -a | xargs docker rm

删除所有停止运行的容器

1
docker rm $( docker ps -q -f status=exited)

删除所有 dangling (unused) 的镜像

php function

url、路径

parse_url

mixed parse_url ( string $url [, int $component = -1 ] )

解析 URL,返回其组成部分

本函数不是用来验证给定 URL 的合法性的
本函数不能用于相对 URL
对严重不合格的 URL,parse_url() 可能会返回 FALSE

parse_str

void parse_str ( string $str [, array &$arr ] )

将字符串解析成多个变量

获取当前的 QUERY_STRING,你可以使用 $_SERVER[‘QUERY_STRING’] 变量
magic_quotes_gpc 影响到了 parse_str() 这个函数的输出,和 PHP 用于填充 $_GET、 $_POST 及其他变量的机制一致

pathinfo

快捷键

mac

CMD-Shift-3
全屏截图

CMD-Shift-4
区域截图:选区
⇧Shift - 重新定义截图区域的纵向高度或横向长度,不能同时实现。
⌥Option - 重新定义截图区域的尺寸,可以同时实现纵向和横向的改变,但只能围绕中心区域展开。
⌴空格键 - 按住并拖动鼠标,可以移动截图选框位置。
Escape(Esc)键 - 退出截图模式。

CMD-Shift-4 + 空格键
区域截图:窗口

screencapture -T +等待时间(秒)+保存的截图名称及格式
抓图

phpStorm

  • command + r 查找替换
  • command + e 打开最近的文件
  • command + shift + o 快速查询文件
  • command + shift + f 关键字查找,更强大的查询器(机器不好的,最好还是先确定一下目录)
  • command + shift + r 高级替换
  • command + alt + b 找到当前类的所有子类
  • alt + shift + c 查找最近修改的文件
  • alt + f7 直接查询选中的字符
  • ctrl + f7 文件中查询选中字符
  • command + shift + +,- 展开或缩起
  • command + . 折叠或展开选中的代码

  • alt + 回车 导入包,自动修正

  • command + n 快事为每个成员属性生成 getter 及 setter 方法
  • ctrl + i 快速生成插入魔术方法
  • ctrol + o 复写父类方法
  • command + alt + l 对当前文件进行格式化排版
  • command + d 复制当剪行
  • command + / // 注释
  • command + shift + / // 注释
  • command + k 提交代码
  • command + shif + k 提交远程分支

利用 CURL 进行数据抓取总结

POST

CURLOPT_POST 的设置可以指定当前提交是否为POST方式

CURLOPT_POSTFIELDS则用于设定提交的参数,可以是参数串,也可以是参数数组

Referer

对于一些程序,它可能判断来源网址,如果发现referer不是自己的网站,则拒绝访问,这时候,我们就需要添加CURLOPT_REFERER参数

cookie支持

对于模拟登录的应用,单单提交参数和模拟来路并不能解决问题,这时候我们就需要保存或者提交相应的Cookie参数

CURLOPT_COOKIE: 直接使用字符串方式提交cookie参数

CURLOPT_COOKIEFILE: 使用文件方式提交cookie参数

CURLOPT_COOKIEJAR: 保存提交后反馈的cookie数据

js 中对 checkbox 的操作

设置值

原生js

1
2
3
4
// Check
document.getElementById("checkbox").checked = true;
// Uncheck
document.getElementById("checkbox").checked = false;

jQuery (1.6+):

1
2
3
4
// Check
$("#checkbox").prop("checked", true);
// Uncheck
$("#checkbox").prop("checked", false);

jQuery (1.5-):

1
2
3
4
// Check
$("#checkbox").attr("checked", true);
// Uncheck
$("#checkbox").attr("checked", false);

1
2
3
4
//Check
document.getElementById('checkbox').setAttribute('checked', 'checked');
//UnCheck
document.getElementById('checkbox').removeAttribute('checked');

get checked

1
2
3
4
5
6
7
// traditional attr
$('#checkMeOut').attr('checked'); // "checked"
// new property method
$('#checkMeOut').prop('checked'); // true
$("#txtAge").get(0).checked
$("#txtAge").is(":checked")

常用代码片段

html utf-8

1
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
1
2
3
header('Content-Type: application/json; charset=utf-8');
header('Content-Type: text/html; charset=utf-8');

常用正则技巧总结

正则字符

  1. .匹配不包括换行的任意字符,在php的s修饰符下面可以匹配换行
  2. \s空格、tab
  3. []单字符取一个,比如[abc]会匹配a或b或c
  4. |多个数据选一(常用于多字符)|的作用域是一直往后直到遇到括号
  5. (?:)非捕获组

技巧

  1. 如果源字符串有换行,使用[\s\S]替换

注意

[]内符号

  • ^在首位时候才有特殊意义
  • -在不是首尾的时候有特殊意义
  • \本身是转义符,有特殊意义

高级技巧

  1. 从大到小,一块块分解

    1. 65530-65535 ==> 6553[0-5] 末位区间0-5
    2. 65500-65529 ==> 655[0-2][0-9] 第四位区间0-2,末位区间0-9
    3. 65000-65499 ==> 65[0-4][0-9]{2} 第三位区间0-4,后两位0-9
    4. 60000-64999 ==> 6[0-4][0-9]{3} 第二位区间0-4,后三位0-9
    5. 10000-59999 ==> [1-5][0-9]{4} 第一位区间1-5,后四位0-9
    6. 1-9999 ==> [1-9][0-9]{0,3} 第一位只能是1-9,后三位可有可无

      最后组合起来:
      (6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{0,3})

      根据数据处理需求,可以在正则前后加上^和$,以匹配整个数据串,或者前后加入\b,把它当做单词边界处理。没有限定字符的边界往往是js正则判断中常见的错误之一。

  2. 贪婪模式与非贪婪模式

    什么时候使用贪婪模式,什么时候使用非贪婪模式,哪个性能好,哪个性能不好,不能一概而论,要根据情况分析。

    不过,在平时的时候用,一般使用非贪婪模式较多,因为贪婪模式经常会由于元字符范围限制不严谨而导致匹配越界,得到非预期结果。

    在确定的数据结构里,可以尝试使用[^>]*>这样的排除字符贪婪模式替换非贪婪模式,提升匹配的效率

    无论使用贪婪模式还是非贪婪模式,在不同语言需要注意回溯次数和嵌套次数的限制,比如在PHP中,pcre.backtrack_limit=100000,pcre.recursion_limit=100000。

  3. 环视(断言/零宽断言)

    环视,在不同的地方又称之为零宽断言,简称断言。

    环视主要有以下4个用法:
    (?<=exp) 匹配前面是exp的数据
    (?=exp) 匹配后面是exp的数据
    (?!exp) 匹配后面不是exp的数据
    (?<!exp) 匹配前面不是exp的数据

    另外,还会看到(?!B)[A-Z]这种写法,其实它是[A-Z]范围里,排除B的意思,前置的(?!B)只是对后面数据的一个限定,从而达到过滤匹配的效果。

    环视部分是不占宽度的,所以有零宽断言的叫法。
    所谓不占宽度,可以分成两部分理解:
    1、环视的匹配结果不纳入数据结果
    2、环视它匹配过的地方,下次还能用它继续匹配。

  4. 模式修饰符

    i不区分大小写
    s的作用主要是让·能够匹配换行