1、web 操作中,当你输入一个 url 到看到页面,描述一下这中间发生了什么?
我想对于很多非 CS 专业的人来说,排名最高的答案可能过于专业,很难看完并且看明白。
而且大家可能只是想了解一下,所以我就写了这么一篇答案,中间跳过了很多细节,并且
也没有说如果发生了错误什么的要怎样之类的。
我们假设 Chrome 浏览器是专门负责根据 URL 寻找并打开网页的人。
-----------
昨天,Chrome 先生的老板给了他一个 URL 地址,并对他说:“去吧,Chrome!”
步骤 0:识别 URL
Chrome 先生低头看了看老板给的 URL,完整的 URL 是由协议(比如 http,ftp)、域名(比
如 http://www.baidu.com)、文件路径(比如/htm_data/20/1510/1441477.html 这样的)和
端口(比如:80)四个部分组成的,老板只给了域名 http://www.zhihu.com,不过没关系。
“这就够了。”Chrome 先生自信的一笑,走向了老板。
步骤 1.查找本地 hosts 文件
“虽然老板已经给了我 URL 地址,但是网页(文件)是保存在服务器上的,要找到老板要
的东西就要找到保存文件的服务器,要找到服务器就要先知道服务器的 IP 地址。”Chrome
先生如是想。
Chrome 从老板的抽屉里找出一个笔记本。
老板好奇的问:“Chrome,为什么每次我要你给我打开个网页你都要看看这个破本子,这
到底是干什么的?”
Chrome:“hosts 文件,用来保存域名以及域名对应的 IP 地址。”
Chrome 打开一看,不出所料,里面空空如也,于是 Chrome 又把笔记本放回了原处。
老板好奇地问:”Chrome,为什么里面是空的?”
“因为你不会科学上网啊,把一个网站的域名写到这个文件里,写一个空格,后面再加上
一个该网站可以用的服务器的 IP 地址,以后访问这个网站的话就会直接访问这个 IP 对应的
服务器了。”
步骤 2.1 询问本地域名服务器
Chrome 看了看手里的域名,“越高级的域名越靠后,必须要先找后面的域名,然后才能进
一步的找到整个域名啊。”
Chrome 用自己的手机拨了一个神秘的电话。
老板好奇的问:“Chrome,你在跟谁打电话?”
Chrome:“地儿,我一朋友,是个本地域名服务器,哎呀你不认识。”
对方很快接通了。
Chrome:”喂,地儿吗?哎对,是我,问你个事儿,www.baidu.com 这个网址你见过
没?……什么?咱们这附近没人上过这个网站?昂……你给我查查?哎……行行行……哎
好嘞,没事,不着急啊。“
说完 Chrome 并没有挂掉电话,依旧把手机放在耳朵边上听着,还抽空跟老板解释了一
句:“根儿也不知道。”
老板好奇的问:“你挂了电话让他打回来不就行了?”
Chrome:“就不。”
2
步骤 2.2 询问根域名服务器
话分两头,这边的本地域名服务器又拿起一部手机,打开了一个叫“找根儿”的 APP。
这个找根儿 APP 是干嘛的呢?顾名思义,就是用来找根域名服务器的了,要知道全世界有
数百个根域名服务器,简而言之,“找根儿”可以帮你找到通话质量最好的那个。
我们还是叫他地儿吧。
地儿:“喂,您好,麻烦帮我查一下 com 这个顶级域名的域名服务器的 IP 地址。”
神秘的对方一号:“好的,您要查的 IP 地址是:2.3.4.5,感谢您的来电,再见。”说完挂
了电话。
地儿又给 2.3.4.5 播了个电话:“喂,您好,我想查一下你们那个 zhihu 的二级域名的域名
服务器地址。”
神秘的对方二号:“好的,您要查的 IP 地址是:3.4.5.6,感谢您的来电,再见。”说完挂
了电话。
地儿又不厌其烦的给 3.4.5.6 拨了个电话:“喂,您好,我想查一下你们那个 wwwl 的三级
域名的域名服务器地址。”
神秘的对方三号:“好的,你要查的 IP 地址是:4.5.6.7,感谢您的来电,再见。”说完挂
了电话。
地儿看了看,地址里没有更低一级的域名了,就拿起跟 Chrome 通话的电话:“哎,
Chrome,还在吧?……对,查出来了……恩,4.5.6.7……恩……恩……好……哎,没事没
事……好,再见,替我跟 IE 问好啊,好长时间没见他了……好……好,再见……哎……
好……好。”
步骤 3.1 根据 IP 地址访问服务器
挂掉了地儿的电话,Chrome 拨通了 4.5.6.7,这时的老板似乎有点等不及了。
很快,对方接通了电话。
神秘的对方四号:“您好,需要什么服务?”
Chrome:“你好,主页就好了。”
神秘的对方四号:“好的,我们注意到您是第一次访问我们页面,现在向您发送确认页
面。”
Chrome:“……什么鬼?”
神秘的对方四号并没有理 Chrome 先生,它发给了 Chrome 先生一个 HTML 文档,Chrome
把这个 HTML 文档解析成了彩色的网页,展示给了老板。
老板输入完用户名、密码还有验证码以后,点击了提交。
这一次 Chrome 不用像第一次那么麻烦了,不过他依然先打开了老板的 hosts 文件看了看,
确定老板没有强制的网址跟 IP 的映射关系(就是某个网址一定要去某个 IP 访问),然后自
己回忆了一下刚刚的操作,就直接拨通了 4.5.6.7。
神秘的对方四号对 Chrome 先生说:“恭喜您登陆成功,现在对您发送一条 cookie 记录,
这样您以后再访问我们网站的时候一块儿把这串 cookie 发过来,我就知道您以前登陆过我
们网站,就不会再出现刚刚的登陆页面了,请注意接收。”
Chrome:”好……“
神秘的对方四号等 Chrome 保存好 cookie 记录之后,接着说:“现在为您跳转到主页,请
注意查收。”
说完,就给 Chrome 发来了一个 html 文件。
Chrome 照例解析这个 html 文件成网页给老板看。
3
Chrome:“没事我先撤了哈。”
2、
HTTP Keep-Alive 的作用
作用:Keep-Alive:使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,
Keep-Alive 功能避免了建立或者重新建立连接。Web 服务器,基本上都支持 HTTP Keep-
Alive。
缺点:对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站
来说,虽然为客户保留打开的连 接有一定的好处,但它同样影响了性能,因为在处理暂停
期间,本来可以释放的资源仍旧被占用。当 Web 服务器和应用服务器在同一台机器上运行
时,Keep- Alive 功能对资源利用的影响尤其突出。
解决:Keep-Alive: timeout=5, max=100
timeout:过期时间 5 秒(对应 httpd.conf 里的参数是:KeepAliveTimeout),max 是最多一
百次请求,强制断掉连接。就是在 timeout 时间内又有新的连接过来,同时 max 会自动减
1,直到为 0,强制断掉。
3、TCP/IP 的请求方式都有哪些?
4、当多个用户同时访问同一网站时,你怎么处理并发?
一层层剥开来讲,有以下部位需要注意。
1.资源。能静态实现的就静态实现,静态资源也要尽量使用分布式存储,例如云存
储。
2.效率。PHP 代码里,尽量注意内存的使用,单个脚本的运行效率要 Ok.
3.缓存。使用 memcache 来实现非持久存储,使用 no-sql 来实现持久存储。
4.server。使用 nginx+fpm 或者 nginx+apache,来实现动静态分离访问。
5.mysql。作为最终的存储库以及一些不可避免的实时调用库,做主从处理,Master+
多 Slave,多个只读副本来实现实时的调用库。
6.负载。建议架设一层负载均衡,来实现 web server 的轮询。例如云平台中的 LBS。
php 是一个语言工具,由 php 来把 apache/nginx/memcache/redis/mysql/httpds 等工具
组合到一起,根据具体的业务需求,选取不同的系统架构模型;高并发其实考验的是系统
的架构
1. 数据的读写层
高并发更多考验的是数据的读写,最终考验的是根据具体的业务需求进行系统的架
构;哪些数据要满足实时读写,哪些数据可以异步读写等要考虑好;数据的读写模型分析
清楚后就要设计数据的存储方案,mysql 擅长的是关系数据和数据统计,但是并发访问是
瓶颈;memcache 擅长的是数据缓存,但 kv 的数据结构有限;redis 作为内存数据库但内存
空间毕竟没有硬盘空间大;
各有优缺点,那么就要根据自己的业务来综合或者选取用这些工具
2. 静态/动态访问
有条件的就使用 cdn,没条件的至少弄一个静态访问层,至于使用 apache 还是 nginx 或
者其它的,自己在虚拟机上都安装一遍,做一个压力测试对比一下
非静态访问转发到动态访问层
3. 逻辑处理即 php
4
到 php 了,php 承接动态访问的输入,进行逻辑运算,最后到数据层去进行读写;
别做太傻的事就可以了,比如无谓的 foreach 循环,复制等操作;再比如,对于实时
访问,对 10 个数据进行排序,就不要再用 mysql 的 select order by 了,直接用 php 的函数
来排序就好了。
一般使用 LVS+PHP 集群(1000 台),就算日均 80 亿次请求,每秒有 10 万并发,那分
到每台机器的请求只有 100 个。只要你的 PHP 程序不是太差,100QPS 总没问题吧?而真
正的瓶颈在于数据库和存储系统,数据的一致性,可扩展性,可用性很难保证。所以需要
根据具体的业务场景再做横向和纵向的分库分表。再辅以 memcache 集群缓存,key-value
高性能存储,异步队列任务系统,整个架构就可以建立起来。还有一类是真正的高并发,
比如 WebIM,一台机器要承受数十万的 TCP 客户端连接,进行大规模的实时通信。这种的
可以用 PHP 的异步高并发扩展 swoole 。
http://www.swoole.com/
5、select 语法结构
虽然 SELECT 语句的完整语法较复杂,但其主要子句可归纳如下:
SELECT select_list
[ INTO new_table]
FROM table_source
[ WHERE search_condition]
[ GROUP BY group_by_expression]
[ HAVING search_condition]
[ ORDER BY order_expression [ ASC|DESC ] ]
必需的子句只有 SELECT 子句和 FROM 子句,其他的子句都是可选的。各子句具体含义如
下:
SELECT 子句:指定由查询返回的列。
INTO 子句:将检索结果存储到新表或视图中。
FROM 子句:用于指定引用的列所在的表或视图。如果对象不止一个,那么它们之间必须
用逗号分开。
WHERE 子句:指定用于限制返回的行的搜索条件。如果 SELECT 语句没有 WHERE 子句,
DBMS 假设目标表中的所有行都满足搜索条件。
GROUP BY 子句:指定用来放置输出行的组,并且如果 SELECT 子句<select list>中包含聚合
函数,则计算每组的汇总值。
HAVING 子句:指定组或聚合的搜索条件。HAVING 通常与 GROUP BY 子句一起使用。如果
不使用 GROUP BY 子句,HAVING 的行为与 WHERE 子句一样。
ORDER BY 子句:指定结果集的排序。ASC 关键字表示升序排列结果,DESC 关键字表示降序
5
排列结果。如果没有指定任何一个关键字,那么 ASC 就是默认的关键字。如果没有 ORDER
BY 子句,DBMS 将根据输入表中的数据的存放位置来显示数据。
6、本地 cookie 是怎样传送给服务器的?
从上图中我们会看到 request header 中自动添加了 Cookie 字段(我并没有手动添加这个字
段哦~),Cookie 字段的值其实就是我设置的那 4 个 cookie。这个请求最终会发送到
http://ppsc.sankuai.com 这个服务器上,这个服务器就能从接收到的 request header 中提取
那 4 个 cookie。
https://segmentfault.com/a/1190000004556040
7、cookie 没有了 session 还有用吗
55 人赞同了该回答
Session 是用户会话,那么要实现用户会话,服务器端应该有个储存会话信息的程序存在。
Session 的服务端服务实现由很多种,常见有磁盘文件保存(PHP 默认方式,会阻塞)、
MySQL(Discuz! 的自己的实现方式)、Memcached(性能较高的一种实现)、Redis。
大致原理就是储存一个独一无二的用户令牌(这里暂且称为 SessionID 吧)和令牌对应的用
户数据,例如这样:
SessionID | UserID
1A6B78E7 | 195
B6SE3C66 | 0 (默认,未登陆状态)
E135C338 | 131 (用户将账号密码验证码和 SessionID 发回服务器后,将 UserID
改为用户主键值)
客户端要实现 Session 就需要从服务端获取一个 SessionID(服务端可以用一个 meta tag 把
SessionID 发到客户端,客户端用 js 获取,方法简直不要太多),永久性或半永久性地保存
在本地(起码不能再开一次网页,会话就没了),每次访问需要 Session 的页面,就将
SessionID 发出。
想到这里,难点就只有两个了,保存和发送。主要难点是前者。
前面有人提到的 URL 传参但没有提到保存方式,永久性或半永久性地储存,除了 Cookie 外
还有什么呢?Etag 单页有效并且缓存容易被冲掉,想了想,HTML5 新增的 LocalStorage 就
可实现近乎永久性的保存。(IE 8+)
解决了客户端接收和储存这个问题,那么发出 SessionID 就简单了:
1、前端模板实现的全异步网站,在需要 SessionID 的请求时,使用:
xhr.setRequestHeader('X-SessionID-Header', 'B6SE3C66');
这样就实现了 SessionID 的收发。
2、非异步网站,粗暴的做法可以让 JS 可以遍历所有 a 标签,判断 host,如果非跨域,则
为其 href 指向链接追加 SessionID 参数,同样实现了收发。当然也还有更加精细的做法。
LocalStorage 虽然不如 Cookie 方便,相对于 Cookie 来说也是有一定好处的,同域的所有页
面请求都会附加上同个 Cookie,这会影响加载速度,很多网站的静态资源都另外使用了一
个域名一部分原因就是这个。LocalStorage 的令牌发送是可控的,Cookie 的发送是不可控
的。
早几年还没 LocalStorage 的时候,我还见过有人在 Cookie 里保存本地草稿,提交前操作
6
Cookie 清除草稿。
这两个东西功能上可以说有些类似,因此一定程度上可以互相替代。
8、简述 HTTP 协议
http://www.jianshu.com/p/4a1cde493ca7
9、三次握手的过程
10、跨域
跨域是指从一个域名的网页去请求另一个域名的资源。比如从 http://www.baidu.com/ 页
面去请求 http://www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,
端口有任何一个的不同,就被当作是跨域。 如何实现跨域取到数据,LS 说的 JSONP 是最
为常见,你可以参考这篇文章 跨域与跨域访问
作者:Notechsolution
链接:https://www.zhihu.com/question/26376773/answer/78442545
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
11、sql 注入,怎么过滤,还有 xss。
12、查看 CPU 磁盘
https://my.oschina.net/hunterli/blog/140783
13、几个详细的项目经历,遇到过什么问题啊,怎么解决的啊
14、Alternative PHP Cache (APC) 是一个开放自由的 PHP opcode 缓存。它的目标是提供一
个自由、 开放,和健全的框架,用于缓存、优化 PHP 中间代码。
15、谈理想
16、分库分表
17、交换
$a=$a^$b;
$b=$a^$b;
$a=$a^$b;
list($a, $b) = array($b, $a);
$a = $a + $b;
$b = $a – $b;
$a = $a – $b;
7
$a = array($a,$b);
$b = $a[0];
$a = $a[1];
$a = $b.','.$a ;
$a = explode(',', $a);
$b = $a[1];
$a = $a[0];
20、PHP 如何获取客户端的 IP 地址
$_SERVER['REMOTE_ADDR'] ; 通过全局数组来获得 用$_SERVER 获取的 IP 地址有什么问
题?
getenv('REMOTE_ADDR') ; 通过环境变量来获得 当客户机使用代理的时候获取不到真实的
IP 地址
21、Select * from user_info Where (ID IN (10, 32, 22)) order BY FIND_IN_SET(ID, '10, 32, 22')
22、写一个函数,尽可能高效的从一个标准 url 中取出扩展名
$arr = parse_url('http://www.sina.com.cn/abc/de/fg.php?id=1');
$result=pathinfo($arr['path']);
var_dump($arr);
var_dump($result['extension']);
23、Apache 与 Nginx 的优缺点比较
nginx 相对于 apache 的优点:
轻量级,比 apache 占用更少的内存及资源。高度模块化的设计,编写模块相对简单
抗并发,nginx 处理请求是异步非阻塞,多个连接(万级别)可以对应一个进程,
而 apache 则是阻塞型的,是同步多进程模型,一个连接对应一个进程,在高并发下 nginx
能保持低资源低消耗高性能
nginx 处理静态文件好,Nginx 静态处理性能比 Apache 高 3 倍以上
apache 相对于 nginx 的优点:
apache 的 rewrite 比 nginx 的 rewrite 强大 ,模块非常多,基本想到的都可以找到 ,比
较稳定,少 bug ,nginx 的 bug 相对较多
原因:这得益于 Nginx 使用了最新的 epoll(Linux 2.6 内核)和 kqueue(freebsd)网络 I/O
模型,而 Apache 则使用的是传统的 select 模型。
目前 Linux 下能够承受高并发访问的 Squid、Memcached 都采用的是 epoll 网络 I/O 模型。
处理大量的连接的读写,Apache 所采用的 select 网络 I/O 模型非常低效。
24、
<?php
class Node{
public $value;
public $left;
public $right;
}
8
function pre($root){
if($root!=null){
echo $root->value.' ';
}
if($root->left!==null){
pre($root->left);
}
if($root->right!==null){
pre($root->right);
}
}
function inner($root){
if($root!==null){
if($root->left!==null){
pre($root->left);
}
if($root!=null){
echo $root->value.' ';
}
if($root->right!==null){
pre($root->right);
}
}
}
function post($root){
if($root->left!==null){
pre($root->left);
}
if($root->right!==null){
pre($root->right);
}
if($root!=null){
echo $root->value.' ';
}
}
function preorder($root){
$stack=array();
array_push($stack,$root);
while(!empty($stack)){
$node=array_pop($stack);
echo $node->value.' ';//先输出根节点
9
if($node->right!=null){
array_push($stack,$node->right);//压入左子树
}
if($node->left!=null){
array_push($stack,$node->left);
}
}
}
function inorder($root){
$stack = array();
$node = $root;
while (!empty($stack) || $node != null) {
while ($node != null) {
array_push($stack, $node);
$node = $node->left;
}
$node = array_pop($stack);
echo $node->value . " ";
$node = $node->right;
}
}
function tailorder($root){
$stack=array();
$outstack=array();
array_push($stack,$root);
while(!empty($stack)){
$node=array_pop($stack);
array_push($outstack,$node);//最先压入根节点,最后输出
if($node->left!=null){
array_push($stack,$node->left);
}
if($node->right!=null){
array_push($stack,$node->right);
}
}
while(!empty($outstack)){
$node=array_pop($outstack);
echo $node->value.' ';
}
}
$a=new Node();
$b=new Node();
10
$c=new Node();
$d=new Node();
$e=new Node();
$f=new Node();
$a->value='A';
$b->value='B';
$c->value='C';
$d->value='D';
$e->value='E';
$f->value='F';
$a->left=$b;
$a->right=$c;
$b->left=$d;
$c->left=$e;
$c->right=$f;
tailorder($a);
我想对于很多非 CS 专业的人来说,排名最高的答案可能过于专业,很难看完并且看明白。
而且大家可能只是想了解一下,所以我就写了这么一篇答案,中间跳过了很多细节,并且
也没有说如果发生了错误什么的要怎样之类的。
我们假设 Chrome 浏览器是专门负责根据 URL 寻找并打开网页的人。
-----------
昨天,Chrome 先生的老板给了他一个 URL 地址,并对他说:“去吧,Chrome!”
步骤 0:识别 URL
Chrome 先生低头看了看老板给的 URL,完整的 URL 是由协议(比如 http,ftp)、域名(比
如 http://www.baidu.com)、文件路径(比如/htm_data/20/1510/1441477.html 这样的)和
端口(比如:80)四个部分组成的,老板只给了域名 http://www.zhihu.com,不过没关系。
“这就够了。”Chrome 先生自信的一笑,走向了老板。
步骤 1.查找本地 hosts 文件
“虽然老板已经给了我 URL 地址,但是网页(文件)是保存在服务器上的,要找到老板要
的东西就要找到保存文件的服务器,要找到服务器就要先知道服务器的 IP 地址。”Chrome
先生如是想。
Chrome 从老板的抽屉里找出一个笔记本。
老板好奇的问:“Chrome,为什么每次我要你给我打开个网页你都要看看这个破本子,这
到底是干什么的?”
Chrome:“hosts 文件,用来保存域名以及域名对应的 IP 地址。”
Chrome 打开一看,不出所料,里面空空如也,于是 Chrome 又把笔记本放回了原处。
老板好奇地问:”Chrome,为什么里面是空的?”
“因为你不会科学上网啊,把一个网站的域名写到这个文件里,写一个空格,后面再加上
一个该网站可以用的服务器的 IP 地址,以后访问这个网站的话就会直接访问这个 IP 对应的
服务器了。”
步骤 2.1 询问本地域名服务器
Chrome 看了看手里的域名,“越高级的域名越靠后,必须要先找后面的域名,然后才能进
一步的找到整个域名啊。”
Chrome 用自己的手机拨了一个神秘的电话。
老板好奇的问:“Chrome,你在跟谁打电话?”
Chrome:“地儿,我一朋友,是个本地域名服务器,哎呀你不认识。”
对方很快接通了。
Chrome:”喂,地儿吗?哎对,是我,问你个事儿,www.baidu.com 这个网址你见过
没?……什么?咱们这附近没人上过这个网站?昂……你给我查查?哎……行行行……哎
好嘞,没事,不着急啊。“
说完 Chrome 并没有挂掉电话,依旧把手机放在耳朵边上听着,还抽空跟老板解释了一
句:“根儿也不知道。”
老板好奇的问:“你挂了电话让他打回来不就行了?”
Chrome:“就不。”
2
步骤 2.2 询问根域名服务器
话分两头,这边的本地域名服务器又拿起一部手机,打开了一个叫“找根儿”的 APP。
这个找根儿 APP 是干嘛的呢?顾名思义,就是用来找根域名服务器的了,要知道全世界有
数百个根域名服务器,简而言之,“找根儿”可以帮你找到通话质量最好的那个。
我们还是叫他地儿吧。
地儿:“喂,您好,麻烦帮我查一下 com 这个顶级域名的域名服务器的 IP 地址。”
神秘的对方一号:“好的,您要查的 IP 地址是:2.3.4.5,感谢您的来电,再见。”说完挂
了电话。
地儿又给 2.3.4.5 播了个电话:“喂,您好,我想查一下你们那个 zhihu 的二级域名的域名
服务器地址。”
神秘的对方二号:“好的,您要查的 IP 地址是:3.4.5.6,感谢您的来电,再见。”说完挂
了电话。
地儿又不厌其烦的给 3.4.5.6 拨了个电话:“喂,您好,我想查一下你们那个 wwwl 的三级
域名的域名服务器地址。”
神秘的对方三号:“好的,你要查的 IP 地址是:4.5.6.7,感谢您的来电,再见。”说完挂
了电话。
地儿看了看,地址里没有更低一级的域名了,就拿起跟 Chrome 通话的电话:“哎,
Chrome,还在吧?……对,查出来了……恩,4.5.6.7……恩……恩……好……哎,没事没
事……好,再见,替我跟 IE 问好啊,好长时间没见他了……好……好,再见……哎……
好……好。”
步骤 3.1 根据 IP 地址访问服务器
挂掉了地儿的电话,Chrome 拨通了 4.5.6.7,这时的老板似乎有点等不及了。
很快,对方接通了电话。
神秘的对方四号:“您好,需要什么服务?”
Chrome:“你好,主页就好了。”
神秘的对方四号:“好的,我们注意到您是第一次访问我们页面,现在向您发送确认页
面。”
Chrome:“……什么鬼?”
神秘的对方四号并没有理 Chrome 先生,它发给了 Chrome 先生一个 HTML 文档,Chrome
把这个 HTML 文档解析成了彩色的网页,展示给了老板。
老板输入完用户名、密码还有验证码以后,点击了提交。
这一次 Chrome 不用像第一次那么麻烦了,不过他依然先打开了老板的 hosts 文件看了看,
确定老板没有强制的网址跟 IP 的映射关系(就是某个网址一定要去某个 IP 访问),然后自
己回忆了一下刚刚的操作,就直接拨通了 4.5.6.7。
神秘的对方四号对 Chrome 先生说:“恭喜您登陆成功,现在对您发送一条 cookie 记录,
这样您以后再访问我们网站的时候一块儿把这串 cookie 发过来,我就知道您以前登陆过我
们网站,就不会再出现刚刚的登陆页面了,请注意接收。”
Chrome:”好……“
神秘的对方四号等 Chrome 保存好 cookie 记录之后,接着说:“现在为您跳转到主页,请
注意查收。”
说完,就给 Chrome 发来了一个 html 文件。
Chrome 照例解析这个 html 文件成网页给老板看。
3
Chrome:“没事我先撤了哈。”
2、
HTTP Keep-Alive 的作用
作用:Keep-Alive:使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,
Keep-Alive 功能避免了建立或者重新建立连接。Web 服务器,基本上都支持 HTTP Keep-
Alive。
缺点:对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站
来说,虽然为客户保留打开的连 接有一定的好处,但它同样影响了性能,因为在处理暂停
期间,本来可以释放的资源仍旧被占用。当 Web 服务器和应用服务器在同一台机器上运行
时,Keep- Alive 功能对资源利用的影响尤其突出。
解决:Keep-Alive: timeout=5, max=100
timeout:过期时间 5 秒(对应 httpd.conf 里的参数是:KeepAliveTimeout),max 是最多一
百次请求,强制断掉连接。就是在 timeout 时间内又有新的连接过来,同时 max 会自动减
1,直到为 0,强制断掉。
3、TCP/IP 的请求方式都有哪些?
4、当多个用户同时访问同一网站时,你怎么处理并发?
一层层剥开来讲,有以下部位需要注意。
1.资源。能静态实现的就静态实现,静态资源也要尽量使用分布式存储,例如云存
储。
2.效率。PHP 代码里,尽量注意内存的使用,单个脚本的运行效率要 Ok.
3.缓存。使用 memcache 来实现非持久存储,使用 no-sql 来实现持久存储。
4.server。使用 nginx+fpm 或者 nginx+apache,来实现动静态分离访问。
5.mysql。作为最终的存储库以及一些不可避免的实时调用库,做主从处理,Master+
多 Slave,多个只读副本来实现实时的调用库。
6.负载。建议架设一层负载均衡,来实现 web server 的轮询。例如云平台中的 LBS。
php 是一个语言工具,由 php 来把 apache/nginx/memcache/redis/mysql/httpds 等工具
组合到一起,根据具体的业务需求,选取不同的系统架构模型;高并发其实考验的是系统
的架构
1. 数据的读写层
高并发更多考验的是数据的读写,最终考验的是根据具体的业务需求进行系统的架
构;哪些数据要满足实时读写,哪些数据可以异步读写等要考虑好;数据的读写模型分析
清楚后就要设计数据的存储方案,mysql 擅长的是关系数据和数据统计,但是并发访问是
瓶颈;memcache 擅长的是数据缓存,但 kv 的数据结构有限;redis 作为内存数据库但内存
空间毕竟没有硬盘空间大;
各有优缺点,那么就要根据自己的业务来综合或者选取用这些工具
2. 静态/动态访问
有条件的就使用 cdn,没条件的至少弄一个静态访问层,至于使用 apache 还是 nginx 或
者其它的,自己在虚拟机上都安装一遍,做一个压力测试对比一下
非静态访问转发到动态访问层
3. 逻辑处理即 php
4
到 php 了,php 承接动态访问的输入,进行逻辑运算,最后到数据层去进行读写;
别做太傻的事就可以了,比如无谓的 foreach 循环,复制等操作;再比如,对于实时
访问,对 10 个数据进行排序,就不要再用 mysql 的 select order by 了,直接用 php 的函数
来排序就好了。
一般使用 LVS+PHP 集群(1000 台),就算日均 80 亿次请求,每秒有 10 万并发,那分
到每台机器的请求只有 100 个。只要你的 PHP 程序不是太差,100QPS 总没问题吧?而真
正的瓶颈在于数据库和存储系统,数据的一致性,可扩展性,可用性很难保证。所以需要
根据具体的业务场景再做横向和纵向的分库分表。再辅以 memcache 集群缓存,key-value
高性能存储,异步队列任务系统,整个架构就可以建立起来。还有一类是真正的高并发,
比如 WebIM,一台机器要承受数十万的 TCP 客户端连接,进行大规模的实时通信。这种的
可以用 PHP 的异步高并发扩展 swoole 。
http://www.swoole.com/
5、select 语法结构
虽然 SELECT 语句的完整语法较复杂,但其主要子句可归纳如下:
SELECT select_list
[ INTO new_table]
FROM table_source
[ WHERE search_condition]
[ GROUP BY group_by_expression]
[ HAVING search_condition]
[ ORDER BY order_expression [ ASC|DESC ] ]
必需的子句只有 SELECT 子句和 FROM 子句,其他的子句都是可选的。各子句具体含义如
下:
SELECT 子句:指定由查询返回的列。
INTO 子句:将检索结果存储到新表或视图中。
FROM 子句:用于指定引用的列所在的表或视图。如果对象不止一个,那么它们之间必须
用逗号分开。
WHERE 子句:指定用于限制返回的行的搜索条件。如果 SELECT 语句没有 WHERE 子句,
DBMS 假设目标表中的所有行都满足搜索条件。
GROUP BY 子句:指定用来放置输出行的组,并且如果 SELECT 子句<select list>中包含聚合
函数,则计算每组的汇总值。
HAVING 子句:指定组或聚合的搜索条件。HAVING 通常与 GROUP BY 子句一起使用。如果
不使用 GROUP BY 子句,HAVING 的行为与 WHERE 子句一样。
ORDER BY 子句:指定结果集的排序。ASC 关键字表示升序排列结果,DESC 关键字表示降序
5
排列结果。如果没有指定任何一个关键字,那么 ASC 就是默认的关键字。如果没有 ORDER
BY 子句,DBMS 将根据输入表中的数据的存放位置来显示数据。
6、本地 cookie 是怎样传送给服务器的?
从上图中我们会看到 request header 中自动添加了 Cookie 字段(我并没有手动添加这个字
段哦~),Cookie 字段的值其实就是我设置的那 4 个 cookie。这个请求最终会发送到
http://ppsc.sankuai.com 这个服务器上,这个服务器就能从接收到的 request header 中提取
那 4 个 cookie。
https://segmentfault.com/a/1190000004556040
7、cookie 没有了 session 还有用吗
55 人赞同了该回答
Session 是用户会话,那么要实现用户会话,服务器端应该有个储存会话信息的程序存在。
Session 的服务端服务实现由很多种,常见有磁盘文件保存(PHP 默认方式,会阻塞)、
MySQL(Discuz! 的自己的实现方式)、Memcached(性能较高的一种实现)、Redis。
大致原理就是储存一个独一无二的用户令牌(这里暂且称为 SessionID 吧)和令牌对应的用
户数据,例如这样:
SessionID | UserID
1A6B78E7 | 195
B6SE3C66 | 0 (默认,未登陆状态)
E135C338 | 131 (用户将账号密码验证码和 SessionID 发回服务器后,将 UserID
改为用户主键值)
客户端要实现 Session 就需要从服务端获取一个 SessionID(服务端可以用一个 meta tag 把
SessionID 发到客户端,客户端用 js 获取,方法简直不要太多),永久性或半永久性地保存
在本地(起码不能再开一次网页,会话就没了),每次访问需要 Session 的页面,就将
SessionID 发出。
想到这里,难点就只有两个了,保存和发送。主要难点是前者。
前面有人提到的 URL 传参但没有提到保存方式,永久性或半永久性地储存,除了 Cookie 外
还有什么呢?Etag 单页有效并且缓存容易被冲掉,想了想,HTML5 新增的 LocalStorage 就
可实现近乎永久性的保存。(IE 8+)
解决了客户端接收和储存这个问题,那么发出 SessionID 就简单了:
1、前端模板实现的全异步网站,在需要 SessionID 的请求时,使用:
xhr.setRequestHeader('X-SessionID-Header', 'B6SE3C66');
这样就实现了 SessionID 的收发。
2、非异步网站,粗暴的做法可以让 JS 可以遍历所有 a 标签,判断 host,如果非跨域,则
为其 href 指向链接追加 SessionID 参数,同样实现了收发。当然也还有更加精细的做法。
LocalStorage 虽然不如 Cookie 方便,相对于 Cookie 来说也是有一定好处的,同域的所有页
面请求都会附加上同个 Cookie,这会影响加载速度,很多网站的静态资源都另外使用了一
个域名一部分原因就是这个。LocalStorage 的令牌发送是可控的,Cookie 的发送是不可控
的。
早几年还没 LocalStorage 的时候,我还见过有人在 Cookie 里保存本地草稿,提交前操作
6
Cookie 清除草稿。
这两个东西功能上可以说有些类似,因此一定程度上可以互相替代。
8、简述 HTTP 协议
http://www.jianshu.com/p/4a1cde493ca7
9、三次握手的过程
10、跨域
跨域是指从一个域名的网页去请求另一个域名的资源。比如从 http://www.baidu.com/ 页
面去请求 http://www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,
端口有任何一个的不同,就被当作是跨域。 如何实现跨域取到数据,LS 说的 JSONP 是最
为常见,你可以参考这篇文章 跨域与跨域访问
作者:Notechsolution
链接:https://www.zhihu.com/question/26376773/answer/78442545
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
11、sql 注入,怎么过滤,还有 xss。
12、查看 CPU 磁盘
https://my.oschina.net/hunterli/blog/140783
13、几个详细的项目经历,遇到过什么问题啊,怎么解决的啊
14、Alternative PHP Cache (APC) 是一个开放自由的 PHP opcode 缓存。它的目标是提供一
个自由、 开放,和健全的框架,用于缓存、优化 PHP 中间代码。
15、谈理想
16、分库分表
17、交换
$a=$a^$b;
$b=$a^$b;
$a=$a^$b;
list($a, $b) = array($b, $a);
$a = $a + $b;
$b = $a – $b;
$a = $a – $b;
7
$a = array($a,$b);
$b = $a[0];
$a = $a[1];
$a = $b.','.$a ;
$a = explode(',', $a);
$b = $a[1];
$a = $a[0];
20、PHP 如何获取客户端的 IP 地址
$_SERVER['REMOTE_ADDR'] ; 通过全局数组来获得 用$_SERVER 获取的 IP 地址有什么问
题?
getenv('REMOTE_ADDR') ; 通过环境变量来获得 当客户机使用代理的时候获取不到真实的
IP 地址
21、Select * from user_info Where (ID IN (10, 32, 22)) order BY FIND_IN_SET(ID, '10, 32, 22')
22、写一个函数,尽可能高效的从一个标准 url 中取出扩展名
$arr = parse_url('http://www.sina.com.cn/abc/de/fg.php?id=1');
$result=pathinfo($arr['path']);
var_dump($arr);
var_dump($result['extension']);
23、Apache 与 Nginx 的优缺点比较
nginx 相对于 apache 的优点:
轻量级,比 apache 占用更少的内存及资源。高度模块化的设计,编写模块相对简单
抗并发,nginx 处理请求是异步非阻塞,多个连接(万级别)可以对应一个进程,
而 apache 则是阻塞型的,是同步多进程模型,一个连接对应一个进程,在高并发下 nginx
能保持低资源低消耗高性能
nginx 处理静态文件好,Nginx 静态处理性能比 Apache 高 3 倍以上
apache 相对于 nginx 的优点:
apache 的 rewrite 比 nginx 的 rewrite 强大 ,模块非常多,基本想到的都可以找到 ,比
较稳定,少 bug ,nginx 的 bug 相对较多
原因:这得益于 Nginx 使用了最新的 epoll(Linux 2.6 内核)和 kqueue(freebsd)网络 I/O
模型,而 Apache 则使用的是传统的 select 模型。
目前 Linux 下能够承受高并发访问的 Squid、Memcached 都采用的是 epoll 网络 I/O 模型。
处理大量的连接的读写,Apache 所采用的 select 网络 I/O 模型非常低效。
24、
<?php
class Node{
public $value;
public $left;
public $right;
}
8
function pre($root){
if($root!=null){
echo $root->value.' ';
}
if($root->left!==null){
pre($root->left);
}
if($root->right!==null){
pre($root->right);
}
}
function inner($root){
if($root!==null){
if($root->left!==null){
pre($root->left);
}
if($root!=null){
echo $root->value.' ';
}
if($root->right!==null){
pre($root->right);
}
}
}
function post($root){
if($root->left!==null){
pre($root->left);
}
if($root->right!==null){
pre($root->right);
}
if($root!=null){
echo $root->value.' ';
}
}
function preorder($root){
$stack=array();
array_push($stack,$root);
while(!empty($stack)){
$node=array_pop($stack);
echo $node->value.' ';//先输出根节点
9
if($node->right!=null){
array_push($stack,$node->right);//压入左子树
}
if($node->left!=null){
array_push($stack,$node->left);
}
}
}
function inorder($root){
$stack = array();
$node = $root;
while (!empty($stack) || $node != null) {
while ($node != null) {
array_push($stack, $node);
$node = $node->left;
}
$node = array_pop($stack);
echo $node->value . " ";
$node = $node->right;
}
}
function tailorder($root){
$stack=array();
$outstack=array();
array_push($stack,$root);
while(!empty($stack)){
$node=array_pop($stack);
array_push($outstack,$node);//最先压入根节点,最后输出
if($node->left!=null){
array_push($stack,$node->left);
}
if($node->right!=null){
array_push($stack,$node->right);
}
}
while(!empty($outstack)){
$node=array_pop($outstack);
echo $node->value.' ';
}
}
$a=new Node();
$b=new Node();
10
$c=new Node();
$d=new Node();
$e=new Node();
$f=new Node();
$a->value='A';
$b->value='B';
$c->value='C';
$d->value='D';
$e->value='E';
$f->value='F';
$a->left=$b;
$a->right=$c;
$b->left=$d;
$c->left=$e;
$c->right=$f;
tailorder($a);