新聞中心
本篇文章給大家整理分享28個關于php核心技術的面試題,帶大家深入了解PHP核心技術,在面試時可以快速避坑,跳槽必備,值得收藏學習,希望對大家有所幫助!

七里河網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁設計、網(wǎng)站建設、微信開發(fā)、APP開發(fā)、成都響應式網(wǎng)站建設公司等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)建站成立于2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設就選創(chuàng)新互聯(lián)建站。
答:oop是面向?qū)ο缶幊?面向?qū)ο缶幊淌且环N計算機編程架構(gòu),OOP 的一條基本原則是計算機程序是由單個能夠起到子程序作用的單元或?qū)ο蠼M合而成。
OOP具有三大特點
1、封裝性:也稱為信息隱藏,就是將一個類的使用和實現(xiàn)分開,只保留部分接口和方法與外部聯(lián)系,或者說只公開了一些供開發(fā)人員使用的方法。于是開發(fā)人員只 需要關注這個類如何使用,而不用去關心其具體的實現(xiàn)過程,這樣就能實現(xiàn)MVC分工合作,也能有效避免程序間相互依賴,實現(xiàn)代碼模塊間松藕合。
2、繼承性:就是子類自動繼承其父級類中的屬性和方法,并可以添加新的屬性和方法或者對部分屬性和方法進行重寫。繼承增加了代碼的可重用性。PHP只支持單繼承,也就是說一個子類只能有一個父類。
3、多態(tài)性:子類繼承了來自父級類中的屬性和方法,并對其中部分方法進行重寫。于是多個子類中雖然都具有同一個方法,但是這些子類實例化的對象調(diào)用這些相同的方法后卻可以獲得完全不同的結(jié)果,這種技術就是多態(tài)性。
多態(tài)性增強了軟件的靈活性。
1、易維護
采用面向?qū)ο笏枷朐O計的結(jié)構(gòu),可讀性高,由于繼承的存在,即使改變需求,那么維護也只是在局部模塊,所以維護起來是非常方便和較低成本的。
2、質(zhì)量高
在設計時,可重用現(xiàn)有的,在以前的項目的領域中已被測試過的類使系統(tǒng)滿足業(yè)務需求并具有較高的質(zhì)量。
3、效率高
在軟件開發(fā)時,根據(jù)設計的需要對現(xiàn)實世界的事物進行抽象,產(chǎn)生類。使用這樣的方法解決問題,接近于日常生活和自然的思考方式,勢必提高軟件開發(fā)的效率和質(zhì)量。
4、易擴展
由于繼承、封裝、多態(tài)的特性,自然設計出高內(nèi)聚、低耦合的系統(tǒng)結(jié)構(gòu),使得系統(tǒng)更靈活、更容易擴展,而且成本較低。
2 合并兩個數(shù)組有幾種方式,試比較它們的異同
方式:
1、array_merge()
2、’+’
3、array_merge_recursive
異同:
array_merge 簡單的合并數(shù)組
array_merge_recursive 合并兩個數(shù)組,如果數(shù)組中有完全一樣的數(shù)據(jù),將它們遞歸合并
array_combine 和 ‘+’ :合并兩個數(shù)組,前者的值作為新數(shù)組的鍵
3 PHP的is_writeable()函數(shù)存在Bug,無法準確判斷一個目錄/文件是否可寫,請寫一個函數(shù)來判斷目錄/文件是否絕對可寫
答:其中bug存在兩個方面,
1、在windowns中,當文件只有只讀屬性時,is_writeable()函數(shù)才返回false,當返回true時,該文件不一定是可寫的。
如果是目錄,在目錄中新建文件并通過打開文件來判斷;
如果是文件,可以通過打開文件(fopen),來測試文件是否可寫。
2、在Unix中,當php配置文件中開啟safe_mode時(safe_mode=on),is_writeable()同樣不可用。
讀取配置文件是否safe_mode是否開啟。
/**
* Tests for file writability
*
* is_writable() returns TRUE on Windows servers when you really can't write to
* the file, based on the read-only attribute. is_writable() is also unreliable
* on Unix servers if safe_mode is on.
*
* @access private
* @return void
*/
if ( ! function_exists('is_really_writable'))
{
function is_really_writable($file){
// If we're on a Unix server with safe_mode off we call is_writable
if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE){
return is_writable($file);
}
// For windows servers and safe_mode "on" installations we'll actually
// write a file then read it. Bah...
if (is_dir($file)){
$file = rtrim($file, '/').'/'.md5(mt_rand(1,100).mt_rand(1,100));
if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE){
return FALSE;
}
fclose($fp);
@chmod($file, DIR_WRITE_MODE);
@unlink($file);
return TRUE;
} elseif ( ! is_file($file) OR ($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) {
return FALSE;
}
fclose($fp);
return TRUE;
}
}
4 PHP的垃圾收集機制是怎樣的?
PHP可以自動進行內(nèi)存管理,清除不再需要的對象。PHP使用了引用計數(shù)(reference counting)這種單純的垃圾回收(garbage collection)機制。
每個對象都內(nèi)含一個引用計數(shù)器,每個reference連接到對象,計數(shù)器加1。當reference離開生存空間或被設為NULL,計數(shù)器減1。當某個對象的引用計數(shù)器為零時,PHP知道你將不再需要使用這個對象,釋放其所占的內(nèi)存空間。
5 寫一個函數(shù),盡可能高效的,從一個標準url里取出文件的擴展名,
例如:http://www.startphp.cn/abc/de/fg.php?id=1需要取出php或.php
http [host] => www.startphp.cn [path] => /abc/de/fg.php [query] => id=1 )
$file = basename($arr['path']);
$ext = explode('.', $file);
return $ext[count($ext)-1];
}
// 方案二
function getExt2($url){
$url = basename($url);
$pos1 = strpos($url,'.');
$pos2 = strpos($url,'?');
if (strstr($url,'?')) {
return substr($url,$pos1+1,$pos2-$pos1-1);
} else {
return substr($url,$pos1);
}
}
$path = "http://www.startphp.cn/abc/de/fg.php?id=1";
echo getExt1($path);
echo "
";
echo getExt2($path);
?>
6 使用正則表達式提取一段標識語言(html或xml)
代碼段中指定標簽的指定屬性值(需考慮屬性值對不規(guī)則的情況,如大小寫不敏感,屬性名值與等號間有空格等)。此處假設需提取test標簽的attr屬性值,請自行構(gòu)建包含該標簽的串(騰訊)
如下:
/i";
$arr=array();
$re=preg_match($pattern1,$str,$arr);
if($re){
echo"
$arr[6]={$arr[6]}";
}else{
echo"
沒找到。";
}
}
// 示例
$str1="";
getAttrValue($str1,"test","attr");//找test標簽中attr屬性的值,結(jié)果為ddd
$str2="";
getAttrValue($str2,"test2","t1");//找test2標簽中t1屬性的值,結(jié)果為t1 value
?>
7 php中WEB上傳文件的原理是什么,如何限制上傳文件的大小?
上傳文件的表單使用post方式,并且要在form中添加enctype='multipart/form-data'。
一般可以加上隱藏域:,位置在file域前面。
value的值是上傳文件的客戶端字節(jié)限制??梢员苊庥脩粼诨〞r間等待上傳大文件之后才發(fā)現(xiàn)文件過大上傳失敗的麻煩。
使用file文件域來選擇要上傳的文件,當點擊提交按鈕之后,文件會被上傳到服務器中的臨時目錄,在腳本運行結(jié)束時會被銷毀,所以應該在腳本結(jié)束之前,將其移動到服務器上的某個目錄下,可以通過函數(shù)move_uploaded_file()來移動臨時文件,要獲取臨時文件的信息,使用$_FILES。
限制上傳文件大小的因素有:
客戶端的隱藏域MAX_FILE_SIZE的數(shù)值(可以被繞開)。
服務器端的upload_max_filesize,post_max_size和memory_limit。這幾項不能夠用腳本來設置。
自定義文件大小限制邏輯。即使服務器的限制是能自己決定,也會有需要個別考慮的情況。所以這個限制方式經(jīng)常是必要的。
8 請說明 PHP 中傳值與傳引用的區(qū)別,什么時候傳值什么時候傳引用?
按值傳遞:函數(shù)范圍內(nèi)對值的任何改變在函數(shù)外部都會被忽略
按引用傳遞:函數(shù)范圍內(nèi)對值的任何改變在函數(shù)外部也能反映出這些修改
優(yōu)缺點:按值傳遞時,php必須復制值。特別是對于大型的字符串和對象來說,這將會是一個代價很大的操作。按引用傳遞則不需要復制值,對于性能提高很有好處。
9 MySQL數(shù)據(jù)庫中的字段類型varchar和char的主要區(qū)別是什么?
Varchar是變長,節(jié)省存儲空間,char是固定長度。查找效率要char型快,因為varchar是非定長,必須先查找長度,然后進行數(shù)據(jù)的提取,比char定長類型多了一個步驟,所以效率低一些。
10 靜態(tài)化如何實現(xiàn)的?偽靜態(tài)如何實現(xiàn)?
1、 靜態(tài)化指的是頁面靜態(tài)化,也即生成實實在在的靜態(tài)文件,也即不需要查詢數(shù)據(jù)庫就可以直接從文件中獲取數(shù)據(jù),指的是真靜態(tài)。
實現(xiàn)方式主要有兩種:一種是我們在添加信息入庫的時候就生成的靜態(tài)文件,也稱為模板替換技術。一種是用戶在訪問我們的頁面時先判斷是否有對應的緩存文件存在,如果存在就讀緩存,不存在就讀數(shù)據(jù)庫,同時生成緩存文件。
2、偽靜態(tài)不是真正意義上的靜態(tài)化,之所以使用偽靜態(tài),主要是為了SEO推廣,搜索引擎對動態(tài)的文件獲取難度大,不利于網(wǎng)站的推廣。
實習原理是基于Apache或Nginx的rewrite
主要有兩種方式:
一種是直接在配置虛擬機的位置配置偽靜態(tài),這個每次修改完成后需要重啟web服務器。
另一種采用分布式的,可以在網(wǎng)站的根目錄上創(chuàng)建.htaccess的文件,在里面配置相應的重寫規(guī)則來實現(xiàn)偽靜態(tài),這種每次重寫時不需要重啟web服務器,且結(jié)構(gòu)上比較清晰。
11 如何處理負載,高并發(fā)?
1、HTML靜態(tài)化
效率最高、消耗最小的就是純靜態(tài)化的html頁面,所以我們盡可能使我們的 網(wǎng)站上的頁面采用靜態(tài)頁面來實現(xiàn),這個最簡單的方法其實也是最有效的方法。
2、圖片服務器分離
把圖片單獨存儲,盡量減少圖片等大流量的開銷,可以放在一些相關的平臺上,如七牛等
3、數(shù)據(jù)庫集群和庫表散列及緩存
數(shù)據(jù)庫的并發(fā)連接為100,一臺數(shù)據(jù)庫遠遠不夠,可以從讀寫分離、主從復制,數(shù)據(jù)庫集群方面來著手。另外盡量減少數(shù)據(jù)庫的訪問,可以使用緩存數(shù)據(jù)庫如memcache、redis。
4、鏡像:
盡量減少下載,可以把不同的請求分發(fā)到多個鏡像端。
5、負載均衡:
Apache的最大并發(fā)連接為1500,只能增加服務器,可以從硬件上著手,如F5服務器。當然硬件的成本比較高,我們往往從軟件方面著手。
12 PHP7的新特性?
標量類型聲明:PHP 7 中的函數(shù)的形參類型聲明可以是標量了。在 PHP 5 中只能是類名、接口、array 或者 callable (PHP 5.4,即可以是函數(shù),包括匿名函數(shù)),現(xiàn)在也可以使用 string、int、float和 bool 了。
返回值類型聲明:增加了對返回類型聲明的支持。類似于參數(shù)類型聲明,返回類型聲明指明了函數(shù)返回值的類型。可用的類型與參數(shù)聲明中可用的類型相同。
NULL 合并運算符:由于日常使用中存在大量同時使用三元表達式和 isset()的情況,NULL 合并運算符使得變量存在且值不為NULL, 它就會返回自身的值,否則返回它的第二個操作數(shù)。
use 加強:從同一 namespace 導入的類、函數(shù)和常量現(xiàn)在可以通過單個 use 語句 一次性導入了 匿名類:現(xiàn)在支持通過new class 來實例化一個匿名類
13 常見的 PHP 安全性攻擊 SQL注入:
用戶利用在表單字段輸入SQL語句的方式來影響正常的SQL執(zhí)行。
防止:使用mysql_real_escape_string()過濾數(shù)據(jù) 手動檢查每一數(shù)據(jù)是否為正確的數(shù)據(jù)類型 使用預處理語句并綁定變量 參數(shù)化SQL:是指在設計與數(shù)據(jù)庫鏈接并訪問數(shù)據(jù)時,在需要填入數(shù)值或數(shù)據(jù)的地方,使用參數(shù) (Parameter) 來給值,用@或?來表示參數(shù)。
XSS攻擊 :跨站點腳本攻擊,由用戶輸入一些數(shù)據(jù)到你的網(wǎng)站,其中包括客戶端腳本(通常JavaScript)。如果你沒有過濾就輸出數(shù)據(jù)到另一個web頁面,這個腳本將被執(zhí)行。
防止:為了防止XSS攻擊,使用PHP的htmlentities()函數(shù)過濾再輸出到瀏覽器。
CSRF:跨站點請求偽造,是指一個頁面發(fā)出的請求,看起來就像是網(wǎng)站的信任用戶,但是是偽造的
防止:一般來說,確保用戶來自你的表單,并且匹配每一個你發(fā)送出去的表單。有兩點一定要記?。簩τ脩魰挷捎眠m當?shù)陌踩胧?,例?給每一個會話更新id和用戶使用SSL。生成另一個一次性的令牌并將其嵌入表單,保存在會話中(一個會話變量),在提交時檢查它。如laravel中的 _token
代碼注入:代碼注入是利用計算機漏洞通過處理無效數(shù)據(jù)造成的。問題出在,當你不小心執(zhí)行任意代碼,通常通過文件包含。寫得很糟糕的代碼可以允許一個遠程文件包含并執(zhí)行。如許多PHP函數(shù),如require可以包含URL或文件名。
防止代碼注入 過濾用戶輸入 在php.ini中設置禁用allow_url_fopen和allow_url_include。這將禁用require/include/fopen的遠程文件
14 面向?qū)ο蟮奶卣饔心男┓矫?
主要有封裝,繼承,多態(tài)。如果是4個方面則加上:抽象。
封裝:
封裝是保證軟件部件具有優(yōu)良的模塊性的基礎,封裝的目標就是要實現(xiàn)軟件部件的高內(nèi)聚,低耦合,防止程序相互依賴性而帶來的變動影響.
繼承:
在定義和實現(xiàn)一個類的時候,可以在一個已經(jīng)存在的類的基礎之上來進行,把這個已經(jīng)存在的類所定義的內(nèi)容作為自己的內(nèi)容,并可以加入若干新的內(nèi)容,或修改原來的方法使之更適合特殊的需要,這就是繼承。繼承是子類自動共享父類數(shù)據(jù)和方法的機制,這是類之間的一種關系,提高了軟件的可重用性和可擴展性。
多態(tài):
多態(tài)是指程序中定義的引用變量所指向的具體類型和通過該引用變量發(fā)出的方法調(diào)用在編程時并不確定,而是在程序運行期間才確定,即一個引用變量倒底會指向哪個類的實例對象,該引用變量發(fā)出的方法調(diào)用到底是哪個類中實現(xiàn)的方法,必須在由程序運行期間才能決定。
抽象:
抽象就是找出一些事物的相似和共性之處,然后將這些事物歸為一個類,這個類只考慮這些事物的相似和共性之處,并且會忽略與當前主題和目標無關的那些方面,將注意力集中在與當前目標有關的方面。例如,看到一只螞蟻和大象,你能夠想象出它們的相同之處,那就是抽象。
15 說說對SQL語句優(yōu)化有哪些方法?(選擇幾條)
(1)Where子句中:where表之間的連接必須寫在其他Where條件之前,那些可以過濾掉最大數(shù)量記錄的條件必須寫在Where子句的末尾.HAVING最后。
(2)用EXISTS替代IN、用NOT EXISTS替代NOT IN。
(3) 避免在索引列上使用計算
(4)避免在索引列上使用IS NULL和IS NOT NULL
(5)對查詢進行優(yōu)化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
(6)應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描
(7)應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描
16 MySQL數(shù)據(jù)庫作發(fā)布系統(tǒng)的存儲,一天五萬條以上的增量,預計運維三年,怎么優(yōu)化?
(1)設計良好的數(shù)據(jù)庫結(jié)構(gòu),允許部分數(shù)據(jù)冗余,盡量避免join查詢,提高效率。
(2) 選擇合適的表字段數(shù)據(jù)類型和存儲引擎,適當?shù)奶砑铀饕?/p>
(3) 做mysql主從復制讀寫分離。
(4)對數(shù)據(jù)表進行分表,減少單表中的數(shù)據(jù)量提高查詢速度。
(5)添加緩存機制,比如redis,memcached等。
(6)對不經(jīng)常改動的頁面,生成靜態(tài)頁面(比如做ob緩存)。
(7)書寫高效率的SQL。比如 SELECT * FROM TABEL 改為 SELECT field_1, field_2, field_3 FROM TABLE.
17 對于大流量的網(wǎng)站,您采用什么樣的方法來解決各頁面訪問量統(tǒng)計問題?
(1) 確認服務器是否能支撐當前訪問量。
(2) 優(yōu)化數(shù)據(jù)庫訪問。
(3)禁止外部訪問鏈接(盜鏈), 比如圖片盜鏈。
(4)控制文件下載。
(5)做負載均衡,使用不同主機分流。
(6)使用瀏覽統(tǒng)計軟件,了解訪問量,有針對性的進行優(yōu)化。
18 談談你對 mysql 引擎中的 MyISAM與InnoDB的區(qū)別理解?
InnoDB和MyISAM是許多人在使用MySQL時最常用的兩個表類型,這兩個表類型各有優(yōu)劣,視具體應用而定?;镜牟顒e為:MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。MyISAM類型的表強調(diào)的是性能,其執(zhí)行數(shù)度比InnoDB類型更快,但是不提供事務支持,而InnoDB提供事務支持已經(jīng)外部鍵等高級數(shù)據(jù)庫功能。
以下是一些細節(jié)和具體實現(xiàn)的差別:
MyISAM與InnoDB的區(qū)別是什么?
1、 存儲結(jié)構(gòu)
MyISAM:每個MyISAM在磁盤上存儲成三個文件。第一個文件的名字以表的名字開始,擴展名指出文件類型。.frm文件存儲表定義。數(shù)據(jù)文件的擴展名為.MYD (MYData)。索引文件的擴展名是.MYI (MYIndex)。
InnoDB:所有的表都保存在同一個數(shù)據(jù)文件中(也可能是多個文件,或者是獨立的表空間文件),InnoDB表的大小只受限于操作系統(tǒng)文件的大小,一般為2GB。
2、 存儲空間
MyISAM:可被壓縮,存儲空間較小。支持三種不同的存儲格式:靜態(tài)表(默認,但是注意數(shù)據(jù)末尾不能有空格,會被去掉)、動態(tài)表、壓縮表。
InnoDB:需要更多的內(nèi)存和存儲,它會在主內(nèi)存中建立其專用的緩沖池用于高速緩沖數(shù)據(jù)和索引。
3、 可移植性、備份及恢復
MyISAM:數(shù)據(jù)是以文件的形式存儲,所以在跨平臺的數(shù)據(jù)轉(zhuǎn)移中會很方便。在備份和恢復時可單獨針對某個表進行操作。
InnoDB:免費的方案可以是拷貝數(shù)據(jù)文件、備份 binlog,或者用 mysqldump,在數(shù)據(jù)量達到幾十G的時候就相對痛苦了。
4、 事務支持
MyISAM:強調(diào)的是性能,每次查詢具有原子性,其執(zhí)行數(shù)度比InnoDB類型更快,但是不提供事務支持。
InnoDB:提供事務支持事務,外部鍵等高級數(shù)據(jù)庫功能。 具有事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。
5、 AUTO_INCREMENT
MyISAM:可以和其他字段一起建立聯(lián)合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,他可以根據(jù)前面幾列進行排序后遞增。
InnoDB:InnoDB中必須包含只有該字段的索引。引擎的自動增長列必須是索引,如果是組合索引也必須是組合索引的第一列。
6、 表鎖差異
MyISAM:只支持表級鎖,用戶在操作myisam表時,select,update,delete,insert語句都會給表自動加鎖,如果加鎖以后的表滿足insert并發(fā)的情況下,可以在表的尾部插入新的數(shù)據(jù)。
InnoDB:支持事務和行級鎖,是innodb的最大特色。行鎖大幅度提高了多用戶并發(fā)操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。
7、 全文索引
MyISAM:支持 FULLTEXT類型的全文索引
InnoDB:不支持FULLTEXT類型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。
8、 表主鍵
MyISAM:允許沒有任何索引和主鍵的表存在,索引都是保存行的地址。
InnoDB:如果沒有設定主鍵或者非空唯一索引,就會自動生成一個6字節(jié)的主鍵(用戶不可見),數(shù)據(jù)是主索引的一部分,附加索引保存的是主索引的值。
9、 表的具體行數(shù)
MyISAM:保存有表的總行數(shù),如果select count(*) from table;會直接取出出該值。
InnoDB:沒有保存表的總行數(shù),如果使用select count(*) from table;就會遍歷整個表,消耗相當大,但是在加了wehre條件后,myisam和innodb處理的方式都一樣。
10、 CURD操作
MyISAM:如果執(zhí)行大量的SELECT,MyISAM是更好的選擇。
InnoDB:如果你的數(shù)據(jù)執(zhí)行大量的INSERT或UPDATE,出于性能方面的考慮,應該使用InnoDB表。DELETE 從性能上InnoDB更優(yōu),但DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除,在innodb上如果要清空保存有大量數(shù)據(jù)的表,最好使用truncate table這個命令。
11、 外鍵
MyISAM:不支持
InnoDB:支持
通過上述的分析,基本上可以考慮使用InnoDB來替代MyISAM引擎了,原因是InnoDB自身很多良好的特點,比如事務支持、存儲 過程、視圖、行級鎖定等等,在并發(fā)很多的情況下,相信InnoDB的表現(xiàn)肯定要比MyISAM強很多。另外,任何一種表都不是萬能的,只用恰當?shù)尼槍I(yè)務類型來選擇合適的表類型,才能最大的發(fā)揮MySQL的性能優(yōu)勢。如果不是很復雜的Web應用,非關鍵應用,還是可以繼續(xù)考慮MyISAM的,這個具體情況可以自己斟酌。
19 redis 和 memache 緩存的區(qū)別
總結(jié)一:
1.數(shù)據(jù)類型
Redis數(shù)據(jù)類型豐富,支持set list等類型
memcache支持簡單數(shù)據(jù)類型,需要客戶端自己處理復雜對象
2.持久性
redis支持數(shù)據(jù)落地持久化存儲
memcache不支持數(shù)據(jù)持久存儲
3.分布式存儲
redis支持master-slave復制模式
memcache可以使用一致性hash做分布式
value大小不同
memcache是一個內(nèi)存緩存,key的長度小于250字符,單個item存儲要小于1M,不適合虛擬機使用
4.數(shù)據(jù)一致性不同
redis使用的是單線程模型,保證了數(shù)據(jù)按順序提交。
memcache需要使用cas保證數(shù)據(jù)一致性。CAS(Check and Set)是一個確保并發(fā)一致性的機制,屬于“樂觀鎖”范疇;原理很簡單:拿版本號,操作,對比版本號,如果一致就操作,不一致就放棄任何操作
5.cpu利用
redis單線程模型只能使用一個cpu,可以開啟多個redis進程
總結(jié)二:
1.Redis中,并不是所有的數(shù)據(jù)都一直存儲在內(nèi)存中的,這是和Memcached相比一個最大的區(qū)別。
2.Redis不僅僅支持簡單的k/v類型的數(shù)據(jù),同時還提供list,set,hash等數(shù)據(jù)結(jié)構(gòu)的存儲。
3.Redis支持數(shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。
4.Redis支持數(shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤中,重啟的時候可以再次加載進行使用。
我個人認為最本質(zhì)的不同是Redis在很多方面具備數(shù)據(jù)庫的特征,或者說就是一個數(shù)據(jù)庫系統(tǒng),而Memcached只是簡單的K/V緩存
總結(jié)三:
redis和memecache的不同在于:
1、存儲方式:
memecache 把數(shù)據(jù)全部存在內(nèi)存之中,斷電后會掛掉,數(shù)據(jù)不能超過內(nèi)存大小
redis有部份存在硬盤上,這樣能保證數(shù)據(jù)的持久性。
2、數(shù)據(jù)支持類型:
redis在數(shù)據(jù)支持上要比memecache多的多。
3、使用底層模型不同:
新版本的redis直接自己構(gòu)建了VM 機制 ,因為一般的系統(tǒng)調(diào)用系統(tǒng)函數(shù)的話,會浪費一定的時間去移動和請求。
4、運行環(huán)境不同:
redis目前官方只支持Linux 上去行,從而省去了對于其它系統(tǒng)的支持,這樣的話可以更好的把精力用于本系統(tǒng) 環(huán)境上的優(yōu)化,雖然后來微軟有一個小組為其寫了補丁。但是沒有放到主干上
memcache只能當做緩存,cache
redis的內(nèi)容是可以落地的,就是說跟MongoDB有些類似,然后redis也可以作為緩存,并且可以設置master-slave
20 redis消息隊列先進先出需要注意什么?
答:通常使用一個list來實現(xiàn)隊列操作,這樣有一個小限制,所以的任務統(tǒng)一都是先進先出,如果想優(yōu)先處理某個任務就不太好處理了,這就需要讓隊列有優(yōu)先級的概念,我們就可以優(yōu)先處理高級別的任務,實現(xiàn)方式有以下幾種方式:
1)單一列表實現(xiàn):隊列正常的操作是 左進右出(lpush,rpop)為了先處理高優(yōu)先級任務,在遇到高級別任務時,可以直接插隊,直接放入隊列頭部(rpush),這樣,從隊列頭部(右側(cè))獲取任務時,取到的就是高優(yōu)先級的任務(rpop)
2)使用兩個隊列,一個普通隊列,一個高級隊列,針對任務的級別放入不同的隊列,獲取任務時也很簡單,redis的BRPOP命令可以按順序從多個隊列中取值,BRPOP會按照給出的 key 順序查看,并在找到的第一個非空 list 的尾部彈出一個元素,redis> BRPOP list1 list2 0
list1 做為高優(yōu)先級任務隊列 list2 做為普通任務隊列 這樣就實現(xiàn)了先處理高優(yōu)先級任務,當沒有高優(yōu)先級任務時,就去獲取普通任務 方式1 最簡單,但實際應用比較局限,方式3可以實現(xiàn)復雜優(yōu)先級,但實現(xiàn)比較復雜,不利于維護 方式2 是推薦用法,實際應用最為合適
21 Redis如何防止高并發(fā)?
答:其實redis是不會存在并發(fā)問題的,因為他是單進程的,再多的命令都是一個接一個地執(zhí)行的。我們使用的時候,可能會出現(xiàn)并發(fā)問題,比如獲得和設定這一對。Redis的為什么 有高并發(fā)問題?Redis的出身決定等
Redis是一種單線程機制的nosql數(shù)據(jù)庫,基于key-value,數(shù)據(jù)可持久化落盤。由于單線程所以redis本身并沒有鎖的概念,多個客戶端連接并不存在競爭關系,但是利用jedis等客戶端對redis進行并發(fā)訪問時會出現(xiàn)問題。發(fā)生連接超時、數(shù)據(jù)轉(zhuǎn)換錯誤、阻塞、客戶端關閉連接等問題,這些問題均是由于客戶端連接混亂造成。
同時,單線程的天性決定,高并發(fā)對同一個鍵的操作會排隊處理,如果并發(fā)量很大,可能造成后來的請求超時。
在遠程訪問redis的時候,因為網(wǎng)絡等原因造成高并發(fā)訪問延遲返回的問題。
解決辦法
在客戶端將連接進行池化,同時對客戶端讀寫Redis操作采用內(nèi)部鎖synchronized。
服務器角度,利用setnx變向?qū)崿F(xiàn)鎖機制。
22 做秒殺用什么數(shù)據(jù)庫,怎么實現(xiàn)的?
答:因為秒殺的一瞬間,并發(fā)非常大,如果同時請求數(shù)據(jù)庫,會導致數(shù)據(jù)庫的壓力非常大,導致數(shù)據(jù)庫的性能急劇下降,更嚴重的可能會導致數(shù)據(jù)庫服務器宕機。
這時候一般采用內(nèi)存高速緩存數(shù)據(jù)庫redis來實現(xiàn)的,redis是非關系型數(shù)據(jù)庫,redis是單線程的,通過redis的隊列可以完成秒殺過程。
23 什么情況下使用緩存?
答:當用戶第一次訪問應用系統(tǒng)的時候,因為還沒有登錄,會被引導到認證系統(tǒng)中進行登錄;根據(jù)用戶提供的登錄信息,認證系統(tǒng)進行身份校驗,如果通過校驗,應該返回給用戶一個認證的憑據(jù)--ticket;
用戶再訪問別的應用的時候,就會將這個ticket帶上,作為自己認證的憑據(jù),應用系統(tǒng)接受到請求之后會把 ticket送到認證系統(tǒng)進行校驗,檢查ticket的合法性。如果通過校驗,用戶就可以在不用再次登錄的情況下訪問應用系統(tǒng)2和應用系統(tǒng)3了。
實現(xiàn)主要技術點:
1、兩個站點共用一個數(shù)據(jù)驗證系統(tǒng)
2、主要通過跨域請求的方式來實現(xiàn)驗證及session處理。
24 如何解決異常處理?
答: 拋出異常:使用try…catch,異常的代碼放在try代碼塊內(nèi),如果沒有觸發(fā)異常,則代碼繼續(xù)執(zhí)行,如果異常被觸發(fā),就會 拋出一個異常。Catch代碼塊捕獲異常,并創(chuàng)建一個包含異常信息的對象。$e->getMessage(),輸出異常的錯誤信息。
解決異常:使用set_error_handler函數(shù)獲取異常(也可以使用try()和catch()函數(shù)),然后使用set_exception_handler()函數(shù)設置默認的異常處理程序,register_shutdown_function()函數(shù)來執(zhí)行,執(zhí)行機制是,php要把調(diào)入的函數(shù)調(diào)入到內(nèi)存,當頁面所有的php語句都執(zhí)行完成時,再調(diào)用此函數(shù)
25 權限管理(RBAC)的實現(xiàn)?
1.首先創(chuàng)建一張用戶表:id name auto(保存格式為:控制器-方法)
2.然后在后臺中創(chuàng)建一個基類控制器,控制器里封裝一個構(gòu)造方法,當用戶登陸成功后,使用TP框架中封裝好的session函數(shù)獲取保存在服務器中的session id,然后實例化模型,通過用戶id獲取保存在數(shù)據(jù)表中的auth數(shù)據(jù),使用explode函數(shù)分割獲取到的數(shù)據(jù),并使用一個數(shù)組保存起來,然后使用TP框架中封裝好的常量獲取當前控制器和方法,然后把他們組裝成字符串,使用in_array函數(shù)進行判斷該數(shù)組中是否含有當前獲取到的控制器和方法,如果沒有,就提示該用戶沒有權限,如果有就進行下一步操作
26 怎么保證促銷商品不會超賣?
答:這個問題是我們當時開發(fā)時遇到的一個難點,超賣的原因主要是下的訂單的數(shù)目和我們要促銷的商品的數(shù)目不一致導致的,每次總是訂單的數(shù)比我們的促銷商品的數(shù)目要多,當時我們的小組討論了好久,給出了好幾個方案來實現(xiàn):
第一種方案:在每次下訂單前我們判斷促銷商品的數(shù)量夠不夠,不夠不允許下訂單,更改庫存量時加上一個條件,只更改商品庫存大于0的商品的庫存,當時我們使用ab進行壓力測試,當并發(fā)超過500,訪問量超過2000時,還是會出現(xiàn)超賣現(xiàn)象。所以被我們否定了。
第二種方案:使用mysql的事務加排他鎖來解決,首先我們選擇數(shù)據(jù)庫的存儲引擎為innoDB,使用的是排他鎖實現(xiàn)的,剛開始的時候我們測試了下共享鎖,發(fā)現(xiàn)還是會出現(xiàn)超賣的現(xiàn)象。有個問題是,當我們進行高并發(fā)測試時,對數(shù)據(jù)庫的性能影響很大,導致數(shù)據(jù)庫的壓力很大,最終也被我們否定了。
第三種方案:使用文件鎖實現(xiàn)。當用戶搶到一件促銷商品后先觸發(fā)文件鎖,防止其他用戶進入,該用戶搶到促銷品后再解開文件鎖,放其他用戶進行操作。這樣可以解決超賣的問題,但是會導致文件得I/O開銷很大。
最后我們使用了redis的隊列來實現(xiàn)。將要促銷的商品數(shù)量以隊列的方式存入redis中,每當用戶搶到一件促銷商品則從隊列中刪除一個數(shù)據(jù),確保商品不會超賣。這個操作起來很方便,而且效率極高,最終我們采取這種方式來實現(xiàn)
27 商城秒殺的實現(xiàn)?
答:搶購、秒殺是如今很常見的一個應用場景,主要需要解決的問題有兩個:
-
高并發(fā)對數(shù)據(jù)庫產(chǎn)生的壓力
-
競爭狀態(tài)下如何解決庫存的正確減少("超賣"問題)
對于第一個問題,已經(jīng)很容易想到用緩存來處理搶購,避免直接操作數(shù)據(jù)庫,例如使用Redis。
第二個問題,我們可以使用redis隊列來完成,把要秒殺的商品放入到隊列中,因為pop操作是原子的,即使有很多用戶同時到達,也是依次執(zhí)行,文件鎖和事務在高并發(fā)下性能下降很快,當然還要考慮其他方面的東西,比如搶購頁面做成靜態(tài)的,通過ajax調(diào)用接口,其中也可能會出現(xiàn)一個用戶搶多次的情況,這時候需要再加上一個排隊隊列和搶購結(jié)果隊列及庫存隊列。
高并發(fā)情況下,將用戶進入排隊隊列,用一個線程循環(huán)處理從排隊隊列取出一個用戶,判斷用戶是否已在搶購結(jié)果隊列,如果在,則已搶購,否則未搶購,庫存減1,寫數(shù)據(jù)庫,將用戶入結(jié)果隊列。
28 如何處理負載、高并發(fā)?
答:從低成本、高性能和高擴張性的角度來說有如下處理方案:
1、HTML靜態(tài)化
其實大家都知道,效率最高、消耗最小的就是純靜態(tài)化的html頁面,所以我們盡可能使我們的 網(wǎng)站上的頁面采用靜態(tài)頁面來實現(xiàn),這個最簡單的方法其實也是最有效的方法。
2、圖片服務器分離
把圖片單獨存儲,盡量減少圖片等大流量的開銷,可以放在一些相關的平臺上,如騎牛等
3、數(shù)據(jù)庫集群和庫表散列及緩存
數(shù)據(jù)庫的并發(fā)連接為100,一臺數(shù)據(jù)庫遠遠不夠,可以從讀寫分離、主從復制,數(shù)據(jù)庫集群方面來著手。另外盡量減少數(shù)據(jù)庫的訪問,可以使用緩存數(shù)據(jù)庫如memcache、redis。
4、鏡像:
盡量減少下載,可以把不同的請求分發(fā)到多個鏡像端。
5、負載均衡:
Apache的最大并發(fā)連接為1500,只能增加服務器,可以從硬件上著手,如F5服務器。當然硬件的成本比較高,我們往往從軟件方面著手。
負載均衡 (Load Balancing) 建立在現(xiàn)有網(wǎng)絡結(jié)構(gòu)之上,它提供了一種廉價有效透明的方法擴展網(wǎng)絡設備和服務器的帶寬、增加吞吐量、加強網(wǎng)絡數(shù)據(jù)處理能力,同時能夠提高網(wǎng)絡的靈活性和可用性。目前使用最為廣泛的負載均衡軟件是Nginx、LVS、HAProxy。
分別來說下三種的優(yōu)缺點:
Nginx的優(yōu)點是:
工作在網(wǎng)絡的7層之上,可以針對http應用做一些分流的策略,比如針對域名、目錄結(jié)構(gòu),它的正則規(guī)則比HAProxy更為強大和靈活,這也是它目前廣泛流行的主要原因之一,Nginx單憑這點可利用的場合就遠多于LVS了。
Nginx對網(wǎng)絡穩(wěn)定性的依賴非常小,理論上能ping通就就能進行負載功能,這個也是它的優(yōu)勢之一;相反LVS對網(wǎng)絡穩(wěn)定性依賴比較大,這點本人深有體會;
Nginx安裝和配置比較簡單,測試起來比較方便,它基本能把錯誤用日志打印出來。LVS的配置、測試就要花比較長的時間了,LVS對網(wǎng)絡依賴比較大。
可以承擔高負載壓力且穩(wěn)定,在硬件不差的情況下一般能支撐幾萬次的并發(fā)量,負載度比LVS相對小些。
Nginx可以通過端口檢測到服務器內(nèi)部的故障,比如根據(jù)服務器處理網(wǎng)頁返回的狀態(tài)碼、超時等等,并且會把返回錯誤的請求重新提交到另一個節(jié)點,不過其中缺點就是不支持url來檢測。比如用戶正在上傳一個文件,而處理該上傳的節(jié)點剛好在上傳過程中出現(xiàn)故障,Nginx會把上傳切到另一臺服務器重新處理,而LVS就直接斷掉了,如果是上傳一個很大的文件或者很重要的文件的話,用戶可能會因此而不滿。
Nginx不僅僅是一款優(yōu)秀的負載均衡器/反向代理軟件,它同時也是功能強大的Web應用服務器。LNMP也是近幾年非常流行的web架構(gòu),在高流量的環(huán)境中穩(wěn)定性也很好。
Nginx現(xiàn)在作為Web反向加速緩存越來越成熟了,速度比傳統(tǒng)的Squid服務器更快,可以考慮用其作為反向代理加速器。
Nginx可作為中層反向代理使用,這一層面Nginx基本上無對手,唯一可以對比Nginx的就只有 lighttpd了,不過 lighttpd目前還沒有做到Nginx完全的功能,配置也不那么清晰易讀,社區(qū)資料也遠遠沒Nginx活躍。
Nginx也可作為靜態(tài)網(wǎng)頁和圖片服務器,這方面的性能也無對手。還有Nginx社區(qū)非?;钴S,第三方模塊也很多。
Nginx的缺點是:
Nginx僅能支持http、https和Email協(xié)議,這樣就在適用范圍上面小些,這個是它的缺點。
對后端服務器的健康檢查,只支持通過端口來檢測,不支持通過url來檢測。不支持Session的直接保持,但能通過ip_hash來解決。
LVS:使用Linux內(nèi)核集群實現(xiàn)一個高性能、高可用的負載均衡服務器,它具有很好的可伸縮性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。
LVS的優(yōu)點是:
抗負載能力強、是工作在網(wǎng)絡4層之上僅作分發(fā)之用,沒有流量的產(chǎn)生,這個特點也決定了它在負載均衡軟件里的性能最強的,對內(nèi)存和cpu資源消耗比較低。
配置性比較低,這是一個缺點也是一個優(yōu)點,因為沒有可太多配置的東西,所以并不需要太多接觸,大大減少了人為出錯的幾率。
工作穩(wěn)定,因為其本身抗負載能力很強,自身有完整的雙機熱備方案,如LVS+Keepalived,不過我們在項目實施中用得最多的還是LVS/DR+Keepalived。
無流量,LVS只分發(fā)請求,而流量并不從它本身出去,這點保證了均衡器IO的性能不會受到大流量的影響。
應用范圍比較廣,因為LVS工作在4層,所以它幾乎可以對所有應用做負載均衡,包括http、數(shù)據(jù)庫、在線聊天室等等。
LVS的缺點是:
軟件本身不支持正則表達式處理,不能做動靜分離;而現(xiàn)在許多網(wǎng)站在這方面都有較強的需求,這個是Nginx/HAProxy+Keepalived的優(yōu)勢所在。
如果是網(wǎng)站應用比較龐大的話,LVS/DR+Keepalived實施起來就比較復雜了,特別后面有 Windows Server的機器的話,如果實施及配置還有維護過程就比較復雜了,相對而言,Nginx/HAProxy+Keepalived就簡單多了。
HAProxy的特點是:
HAProxy也是支持虛擬主機的。
HAProxy的優(yōu)點能夠補充Nginx的一些缺點,比如支持Session的保持,Cookie的引導;同時支持通過獲取指定的url來檢測后端服務器的狀態(tài)。
HAProxy跟LVS類似,本身就只是一款負載均衡軟件;單純從效率上來講HAProxy會比Nginx有更出色的負載均衡速度,在并發(fā)處理上也是優(yōu)于Nginx的。
HAProxy支持TCP協(xié)議的負載均衡轉(zhuǎn)發(fā),可以對MySQL讀進行負載均衡,對后端的MySQL節(jié)點進行檢測和負載均衡,大家可以用LVS+Keepalived對MySQL主從做負載均衡。
HAProxy負載均衡策略非常多,HAProxy的負載均衡算法現(xiàn)在具體有如下8種:
① roundrobin,表示簡單的輪詢,這個不多說,這個是負載均衡基本都具備的;
② static-rr,表示根據(jù)權重,建議關注;
③ leastconn,表示最少連接者先處理,建議關注;
④ source,表示根據(jù)請求源IP,這個跟Nginx的IP_hash機制類似,我們用其作為解決session問題的一種方法,建議關注;
⑤ ri,表示根據(jù)請求的URI;
⑥ rl_param,表示根據(jù)請求的URl參數(shù)’balance url_param’ requires an URL parameter name;
⑦ hdr(name),表示根據(jù)HTTP請求頭來鎖定每一次HTTP請求;
⑧ rdp-cookie(name),表示根據(jù)據(jù)cookie(name)來鎖定并哈希每一次TCP請求。
Nginx和LVS對比的總結(jié):
Nginx工作在網(wǎng)絡的7層,所以它可以針對http應用本身來做分流策略,比如針對域名、目錄結(jié)構(gòu)等,相比之下LVS并不具備這樣的功能,所以Nginx單憑這點可利用的場合就遠多于LVS了;但Nginx有用的這些功能使其可調(diào)整度要高于LVS,所以經(jīng)常要去觸碰觸碰,觸碰多了,人為出問題的幾率也就會大。
Nginx對網(wǎng)絡穩(wěn)定性的依賴較小,理論上只要ping得通,網(wǎng)頁訪問正常,Nginx就能連得通,這是Nginx的一大優(yōu)勢!Nginx同時還能區(qū)分內(nèi)外網(wǎng),如果是同時擁有內(nèi)外網(wǎng)的節(jié)點,就相當于單機擁有了備份線路;LVS就比較依賴于網(wǎng)絡環(huán)境,目前來看服務器在同一網(wǎng)段內(nèi)并且LVS使用direct方式分流,效果較能得到保證。
另外注意,LVS需要向托管商至少申請多一個ip來做Visual IP,貌似是不能用本身的IP來做VIP的。要做好LVS管理員,確實得跟進學習很多有關網(wǎng)絡通信方面的知識,就不再是一個HTTP那么簡單了。
Nginx安裝和配置比較簡單,測試起來也很方便,因為它基本能把錯誤用日志打印出來。LVS的安裝和配置、測試就要花比較長的時間了;LVS對網(wǎng)絡依賴比較大,很多時候不能配置成功都是因為網(wǎng)絡問題而不是配置問題,出了問題要解決也相應的會麻煩得多。
Nginx也同樣能承受很高負載且穩(wěn)定,但負載度和穩(wěn)定度差LVS還有幾個等級:Nginx處理所有流量所以受限于機器IO和配置;本身的bug也還是難以避免的。
Nginx可以檢測到服務器內(nèi)部的故障,比如根據(jù)服務器處理網(wǎng)頁返回的狀態(tài)碼、超時等等,并且會把返回錯誤的請求重新提交到另一個節(jié)點。目前LVS中 ldirectd也能支持針對服務器內(nèi)部的情況來監(jiān)控,但LVS的原理使其不能重發(fā)請求。比如用戶正在上傳一個文件,而處理該上傳的節(jié)點剛好在上傳過程中出現(xiàn)故障,Nginx會把上傳切到另一臺服務器重新處理,而LVS就直接斷掉了,如果是上傳一個很大的文件或者很重要的文件的話,用戶可能會因此而惱火。
Nginx對請求的異步處理可以幫助節(jié)點服務器減輕負載,假如使用 apache直接對外服務,那么出現(xiàn)很多的窄帶鏈接時apache服務器將會占用大 量內(nèi)存而不能釋放,使用多一個Nginx做apache代理的話,這些窄帶鏈接會被Nginx擋住,apache上就不會堆積過多的請求,這樣就減少了相當多的資源占用。這點使用squid也有相同的作用,即使squid本身配置為不緩存,對apache還是有很大幫助的。
Nginx能支持http、https和email(email的功能比較少用),LVS所支持的應用在這點上會比Nginx更多。在使用上,一般最前端所采取的策略應是LVS,也就是DNS的指向應為LVS均衡器,LVS的優(yōu)點令它非常適合做這個任務。
重要的ip地址,最好交由LVS托管,比如數(shù)據(jù)庫的 ip、webservice服務器的ip等等,這些ip地址隨著時間推移,使用面會越來越大,如果更換ip則故障會接踵而至。所以將這些重要ip交給 LVS托管是最為穩(wěn)妥的,這樣做的唯一缺點是需要的VIP數(shù)量會比較多。
Nginx可作為LVS節(jié)點機器使用,一是可以利用Nginx的功能,二是可以利用Nginx的性能。當然這一層面也可以直接使用squid,squid的功能方面就比Nginx弱不少了,性能上也有所遜色于Nginx。
Nginx也可作為中層代理使用,這一層面Nginx基本上無對手,唯一可以撼動Nginx的就只有l(wèi)ighttpd了,不過lighttpd目前還沒有能做到 Nginx完全的功能,配置也不那么清晰易讀。另外,中層代理的IP也是重要的,所以中層代理也擁有一個VIP和LVS是最完美的方案了。
具體的應用還得具體分析,如果是比較小的網(wǎng)站(日PV小于1000萬),用Nginx就完全可以了,如果機器也不少,可以用DNS輪詢,LVS所耗費的機器還是比較多的;大型網(wǎng)站或者重要的服務,機器不發(fā)愁的時候,要多多考慮利用LVS。
文章名稱:【吐血整理】28個關于PHP核心技術的面試題,助力跳槽!
URL標題:http://www.dlmjj.cn/article/djhohcg.html


咨詢
建站咨詢
