---
# System prepended metadata

title: 天瀚國際科技 後端工程師技術問卷 (20210114)

---

# 天瀚國際科技 後端工程師技術問卷 (20210114)
## 1. 請問您目前主要的技術學習管道為何？（例：某網站，特定書籍等）
github,udemy,biibii,google
## 2. 請舉例在你過去的工作經驗中，覺得面臨過最大的技術挑戰或最令你印象深刻的技術性問題，並分享最後如何解決他？

- 某情境設計下  每一User 會建立各自sqlite , 當使用者數量過多時,讀寫產生異常
    - 橫向擴展磁碟數量,增加IOPS , 將不同User sqlite 分別存儲不同區域磁碟
    - 將每區域的User sqlite 以資料夾分門別類 ,改善查詢至使用者sqlite時間
    - 當個別使用者sqlite db 多個程序同時讀取 會有write-lock,資料需另做處理


## 3. 當 Client 端存取 https://foo.com/api/v1/bar 這個 HTTP API 的位置，請從 DNS 解析到 PHP 解析到最後回傳 Response 內容盡可能完整描述中間所有詳細發生的流程。（以 Nginx + PHP-FPM 的架構為例）

### - DNS 解析階段 
![](https://i.imgur.com/carkSbk.png)

1. 查詢主機hosts文件是否存在domain對應ip,有則返回
2. 根據DNS設定 ,向其發起查詢
3. 查詢是否有緩存 有則返回
4. 向根服務器查詢`.com` 服務器ip
5. .com服務器 取得該domain 所對應ip位置
6. dns服務器返回其domain ip位置
7. 與server 進行連線

### - Nginx + PHP-FPM 連現階段 
- TCP 建立三向握手
- FastCGI master監聽 port, 接收 request 交由某一worker執行 
- 建立https連線
    - Client 發送TLS版本＋加密集資訊＋隨機數
    - Server端 選用雙方共同支援版本及密碼集＋隨機數,同時將證書及公鑰回傳
    - Client 也信任該憑證認證機構,並驗證其證書是否合法,不合法則提出警告
    - Client 創建一個隨機私鑰並用server端公鑰進行加密
    - Server 端利用私鑰解密後獲取隨機私鑰＋雙方隨機數組成會話私鑰
    - 雙方利用會話私鑰加密發送訊息 , 確認服務正常 , https連線建立

- nginx 配置解析
    - location , 比對請求 執行root 所設定位置php程式
    - fast-cgi 將請求拋轉至 php-fpm執行
    - PHP解析器執行程式碼 route處理 `api/v1/bar` 並返回結果 
    - 釋放worker

- 連線結束 TCP 四次揮手 


## 4. 如下有一個票券購買的範例程式，程式會先檢查票券的剩餘數量，若數量足夠則進行票券購買流程並且扣除票券剩餘數量，若票券數量不足則會拋出例外錯誤。請問以下的程式可能存在什麼問題，如果是你會怎麼修改？

- ex : 當A和B瞬間購票行為
兩者都是取到相同票券剩餘數量1000
結果相互執行-1的動作
2筆update記錄為999
正確情況應該為 一筆999, 另一筆998
- A拿到票券剩餘數量資源時
此資源應當處於被鎖定狀態
當A完成update資料時才會釋放資源
然後讓B繼續存取
否則B必須等待A完成釋放資源


```
public function buyTicket(Request $request, Ticket $tickets)
{
    // 1.開始交易
    DB::beginTransaction();
    try {
        // 2.查詢時進行上鎖
        $ticket = Ticket::lockForUpdate()->find($tickets->Id);
        // 3.檢查票券是否還有足夠數量
        if ($ticket->available_amount <= 0) {
            throw new TicketUnavailableException('Ticket amount is not available');
        }

        // 4.中間購買邏輯省略

        // 5.扣除票券剩餘數量(尚未提交)
        $ticket->update([
            'available_number' => $ticket->available_amount - 1;
        ]);
    }catch (\Exception $e) {
        DB::rollback();
        throw new TicketUnavailableException('Error:' + $e->getMessage());
    }
    
    // 6.提交結果
    DB::commit();
    
    return [
        'success' => true
    ];
}
```



