某公司后端開發工程師面試題學習


最近看到的某公司后端開發工程師面試題,拿來研究學習一下,感覺提高技術,看面試題也是一個挺好的方法:(

 1.redis有幾種使用場景,除了使用字符串型還使用過redis哪些存儲類型?
 2.redis如何實現鎖?
 3.php有哪些實現鎖的機制?
 4.myisam和inodb的區別?
 5.什么是ddos攻擊?如何防范ddos攻擊?
 6.http和https有什么不同?http包是如何泄露的? 
 7.php7有什么新特性?
 8.如何防止SQL注入?
 9.mysql主、從數據庫如何保持一致?
10.php如何實現異步機制?
 
 
1.redis的使用場景包括:
   1)緩存數據。一些訪問量大的熱點數據,首頁數據,搜索數據都可以通過redis緩存起來。根本目的是減少數據庫的訪問壓力,提高頁面響應速度和用戶體驗度。極端的做法是,只要可以減輕數據庫壓力,數據都可以緩存。本質是空間換時間。弊端是用戶得到的數據不是實時最新的數據,有一定的延遲(取決於緩存時設置的過期時間);
   2)實現鎖機制。redis實現鎖的方式包括incr,set.setnx。考慮場景,網站提供 將用戶賬戶余額轉賬到用戶支付寶的功能,如果同時並發有多個請求,在賬戶操作和遠程請求支付寶的過程中可能出現數據不一致問題。以incr舉例,加鎖實現單線程阻塞操作:

  Redis Incr 命令將 key 中儲存的數字值增一。

        如果 key 不存在,那么 key 的值會先被初始化為 0 ,然后再執行 INCR 操作。(incr具有原子性。)

//先獲取相關用戶參數並且驗證

$redis_lock = $Redis::incr($user_id."alipay_lock");
if($redis_lock <= 1){
	$redis::expire($redis_lock,10);//設置超時時間

	//數據庫操作
	//向支付寶發送轉賬請求操作

	$Redis::del($redis_lock);
}else{
	//返回提示信息,表示轉賬正在進行
}  
 這里的一個細節是,必須設置超時時間,防止在轉賬相關操作中,出現超時或其他錯誤,鎖沒有解除。其他並發請求永遠無法執行轉賬操作。
  3)會話緩存。web請求的session數據可以存在redis中。把 session 默認的存儲方式由 file 改為  redis 會提高速度,由於redis是在內存中讀取的,其讀取速度必然比在文件中讀取速度快,同時解決了session共享的問題。
參考:https://yann0917.github.io/2017/05/01/PHP-session-%E5%AD%98%E5%85%A5-Redis/
  https://blog.csdn.net/Dennis_ukagaka/article/details/78072274
  4)計數器。數據統計的需求非常普遍,通過原子遞增保持計數。例如,點贊數、收藏數、分享數等。 
  5)排行榜功能,例如,展示最近、最熱、點擊率最高、活躍度最高等等條件的top list 。 利用redis的有序集合實現(sorted set);
  6)簡單的隊列實現。使用list功能。
  參考:https://juejin.im/post/58330053570c350059e0bb08
 
  除了string類型,還用過list數據類型。當時是維護python寫的程序,以前的同學使用list存儲從數據表中查詢出來的數據,感覺這樣不是很好,還是序列化存儲成字符串型較好。
 
 2.前面的答案已經解答了這個問題。
 
 3.1)php可以用文件鎖來實現。參考代碼:
$fp=fopen('/tmp/lock.txt','w+');
if (flock($fp,LOCK_EX)){
   //do something flock($fp,LOCK_UN); }else{ echo 'Couldn't lock the file !'; } fclose($fp);

  打開文件后,先對文件加鎖。加鎖后,意味着只有這個進程可以訪問lock.txt文件 。在操作完成后,打開鎖。這個方法操作比較簡易,對於需要同步執行的程序出錯概率低的情況,較為適用;可是它的缺點是沒有超時時間的限制,一旦在do something的時候出現什么問題。這個鎖就解不開了。會占用cpu。其他進程也無法執行該操作了。

      2)可以用redis緩存實現鎖。前面答案已經描述。這個適用於隨機響應的情況,如果需要響應每一個請求,且按請求的先后順序進行依次處理。則不太適合,應當構建隊列。

      3)使用隊列來響應並發請求(隊列依然依賴redis的list數據結構實現)。來一個排隊一個,依次處理。處理程序可以用php寫一個守護程序。按順序去redis里的list去取請求處理,如果list為空,則等待1秒再去取。(大概邏輯是這樣)。

  4.這個網上答案很多。

      區別:1)myisam的text支持索引,innodb不支持;

                 2)innodb支持事務,myisam不支持,對於InnoDB每一條SQL語言都默認封裝成事務,自動提交,這樣會影響速度,所以最好把多條SQL語言放在begin和commit之間,組成一個事務;

                3)innodb有行鎖,myisam只是表鎖;

                4)myisam的查詢效率高於innodb;

                 5)InnoDB不保存表的具體行數,執行select count(*) from table時需要全表掃描。而MyISAM用一個變量保存了整個表的行數,執行上述語句時只需要讀出該變量即可,速度很快;

                 6)InnoDB支持外鍵,而MyISAM不支持。對一個包含外鍵的InnoDB表轉為MYISAM會失敗;

                7)InnoDB是聚集索引,數據文件是和索引綁在一起的,必須要有主鍵,通過主鍵索引效率很高。但是輔助索引需要兩次查詢,先查詢到主鍵,然后再通過主鍵查詢到數據。因此,主鍵不應該過大,因為主鍵太大,其他索引也都會很大。而MyISAM是非聚集索引,數據文件是分離的,索引保存的是數據文件的指針。主鍵索引和輔助索引是獨立的。

參考:https://www.zhihu.com/question/20596402

5.分布式拒絕服務(DDoS:Distributed Denial of Service)攻擊指借助於客戶/服務器技術,將多個計算機聯合起來作為攻擊平台,對一個或多個目標發動DDoS攻擊,從而成倍地提高拒絕服務攻擊的威力。(來源百度百科)

       如何防范:1)關閉不必要的服務,如只開放80端口響應Http請求;2)獲取可疑攻擊ip,加入黑名單,禁止訪問;3)使用cdn服務,將流量分散到網絡各個節點,減少對服務器的壓力等等。(具體的方法網絡上很多,有各種的總結和攻防的案例)。

6. 簡單來說,http是明文傳輸的協議,客戶端和服務器通訊的所有內容都明文暴露在公共的互聯網上,一旦http包被截獲,信息就會被別人獲取;https則是加密傳輸的協議,客戶端和服務器通訊的關鍵內容都是有密匙加密過的,雖然也是在公共的網絡上傳遞,但是通訊的包被截獲,別人拿到加密后的內容也無法解密獲取到通訊的內容。具體的介紹可以參考前端牛人小卡的一篇介紹,寫的很詳細。雖然https的瀏覽器私人密匙怎么生成我還是不太了解,是不是可以窮舉?  

2018/5/9  服務器發給客戶端的證書的數字簽名,需要客戶端用CA的公匙解密。這個CA的公匙是保存在瀏覽器或者操作系統中的。所以使用php的時候依然可以做https請求!

 

  http包泄露的方式: 1)自己的電腦被入侵,接受和發送的http包都會被黑客監聽獲取到;2)電腦所在的局域網關被黑客入侵,http包也會被截獲;3)在公共互聯網上也有很多節點(如代理服務器)可能被截獲。

7. php7的新特性有很多,最實惠的是性能(無論是服務器的cpu占用率,響應請求數量還是請求處理時間)提高了至少一倍。參考http://hansionxu.blog.163.com/blog/static/24169810920158704014772/,和鳥哥的個人網站。有空我需要再把php的底層實現再看看吧。

8. 防止sql注入的方法:1)嚴格限制用戶輸入(長度,類型,特殊字符);2)使用mysql_escape_string轉義特殊字符;3)使用pdo模式操作數據庫,預編譯語句,參數化查詢,分開的發送到數據庫服務端進行解析。

 具體的php綁定和分預編譯語句,變量參數化兩次傳遞給msql服務器的細節內容可以參考月影無痕的分析。至於將SQL模板和變量是分兩次發送給MySQL后,mysql的處理細節,我繼續使用google。查詢到文章:預編譯語句(Prepared Statements)介紹,以MySQL為例 。里面介紹了預編譯語句在mysql端是如何實現的,但是還是沒有解決我的核心問題,預編譯語句為什么能防止sql注入? 知乎相關問題中,不二的回答提到了占位符的概念很有意思,sql語句在包含占位符的情況下編譯,理論上來說,以后就不會再改變了。這是否決定了該語句的運行結果被限制在一定的范圍內了,后面用參數代替占位符(會將參數字符串轉義)后的結果也會限定在這個范圍內? 有待於進一步研究吧。

 9.MySQL之間數據復制的基礎是二進制日志文件(binary log file)。一台MySQL數據庫一旦啟用二進制日志后,其作為master,它的數據庫中所有操作都會以“事件”的方式記錄在二進制日志中,其他數據庫作為slave通過一個I/O線程與主服務器保持通信,並監控master的二進制日志文件的變化,如果發現master二進制日志文件發生變化,則會把變化復制到自己的中繼日志中,然后slave的一個SQL線程會把相關的“事件”執行到自己的數據庫中,以此實現從數據庫和主數據庫的一致性,也就實現了主從復制。

具體參考:https://www.cnblogs.com/gl-developer/p/6170423.html

 10.php本身並沒有異步處理的機制。如果需要實現異步機制,可以變着法用一些加超時的請求或ajax來完成。
      1)服務器返回的html中插入Ajax 代碼或 img 標記,img的src為需要執行的程序;2)使用popen;3)使用curl,超時設為1秒;4)使用 fsockopen,自己拼參數,可以立即返回不在意超時時間。參考: http://www.jb51.net/article/76909.htm  

 這個時候我又腦洞大開,既然已經想到了php的異步調用了。那么會不會有像其他語言里面一樣的回調函數存在呢,比如js里面的call這樣的。於是google了一樣還真有這樣的東西。不過它是同步文件中的,如果異步調用非得要回調,可以把回調的一些參數放在請求參數中,這樣在請求的文件中調用回調的內容就可以了。

關於php的回調函數實現,可以參考:http://www.cnitblog.com/CoffeeCat/archive/2009/04/21/56541.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM