Springboot 之基於 Serverless 的訂單應用

前言

這是一個 JAVA 開發的訂單後臺應用(沒錯!就是那個讓無數大學生痛不欲生的訂單後臺系統),結合 Serverless 這一無服務器思想,嘗試通過雲函數 + API 網關 + 雲數據庫的組合來部署 Springboot 的成功之作。

本文作者:Freeeeeedom

該應用提供了完整的用戶登錄驗證、接口數據驗證、訂單流 (CRUD) 等強大的功能,而且在本地開發調試時也能模擬 API 網關調用雲函數(本地 Java 開發雲端部署不是問題),還兼容了雲消息隊列 CMQ 的調用,以便後續開發引入雲中間件。

同時,這種部署方式也能讓其他的 Springboot 很快地轉換爲雲函數部署。

爲響應國家「十四五計劃」的環保計劃,特地的研究了一下傳說中的 Serverless 方案(省服務器 😄),於是便有了這次嘗試。

語言和框架

  • JAVA 天下第一**,當然 c/c++/c#/node/python/go/php/vb 這些也不錯
  • JAVA 的單體應用還能選什麼呢?只能是 Springboot 啊

部署準備

  1. 註冊個騰訊雲賬號
  2. 開通以下產品權限(雲函數、API 網關、對象存儲)
  3. 財力允許的話還可以購買數據庫服務(因爲年少輕狂打折時我購買了這倆很長很長時間)
  • mysql數據庫
  • redis數據庫

部署方案

訂單應用來說的話,必然是提供 restful 的接口,所以在統一 VPC 內採用了雲函數 + API 網關的模式提供接口,於是就有了以下方案:

  1. 應用主體部署在雲函數
  2. 使用 API 網關作爲函數入口
  3. 頁面則是使用了對象存儲部署
  4. 數據庫方面則使用了同一 vpc 下的雲數據庫(財力有限只嘗試了 mysql、redis,理論上其他應該都可行)

嘗試部署

要讓 JAVA 工程部署到雲函數上,首先了解什麼是雲函數(以下摘自微信開放文檔)

雲函數即在雲端(服務器端)運行的函數。在物理設計上,一個雲函數可由多個文件組成,佔用一定量的 CPU 內存等計算資源;各雲函數完全獨立;可分別部署在不同的地區。開發者無需購買、搭建服務器,只需編寫函數代碼並部署到雲端即可在小程序端調用,同時雲函數之間也可互相調用。

雲函數其實就是將業務拆分成函數粒度部署在雲上,那麼就寫了個簡單的 demo 部署到雲函數上,並且配上了 API 網關嘗試調用。

 /**
 * 純javascf快速開發部署(不走springboot)
 *
 * @author Freeeeeedom
 * @date 2020/10/24 10:31
 */
public class Scf {
    /**
     * log Object
     */
    private static Logger log = LoggerFactory.getLogger(Scf.class);
    private static DruidDataSource dataSource1 = new DruidDataSource();

    static {
        //此處加載或修改數據源 多數據源配置多個
        dataSource1.setUsername("Freeeeeedom");
        dataSource1.setUrl("jdbc:mysql://Freeeeeedom?autoReconnectForPools=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
        dataSource1.setPassword("Freeeeeedom");
        dataSource1.setMinIdle(1);
        dataSource1.setMaxActive(5);
        dataSource1.setMaxWait(10000);
        dataSource1.setValidationQuery("SELECT 1 from dual");
        log.info("數據源加載ok~");
    }

    /**
     * 純scf入口參數
     *
     * @param insertParam 入參
     * @return java.lang.Object 執行結果
     * @author Freeeeeedom
     * @date 2020/10/24 10:31
     */
    public Object pure(Map<String, Object> insertParam) {
        log.info("param:{}", gson.toJson(insertParam);
        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            log.error("內部處理異常", e);
        }
        Map response = new HashMap();
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource1);
        Map order = jdbcTemplate.queryForMap("select order_id,create_time from `order` limit 1");
        log.info(order.toString());
        return buildResponse(gson, gson.toJson(order), response);
    }

    private Object buildResponse(Gson gson, String json, Map response) {
        Map<String, String> headers = new HashMap(1);
        headers.put("Content-Type", "application/json");
        response.put("statusCode", HttpStatus.OK.value());
        response.put("headers", headers);
        response.put("body", json);
        return gson.toJson(response);
    }
}

只需要打包好代碼,然後將入口函數設置爲 scf.Scf::pure 就實現了接收數據,然後從數據庫查詢了第一個訂單的 id 和創建時間並且返回的能力:

每一次通過 API 網關觸發雲函數都會觸發 pure 這個方法(調用者 > 調用 API 網關 > 雲函數 --> pure),但經測試發現 static 的數據源初始化並不會被重複加載,這也奠定了 springboot 可部署基礎。

其中通過 log 打印 API 網關帶來的參數,直接將其複製爲 json,然後通過 main 函數模擬調用,這樣就實現了本地模擬 serverless 部署後的調用。

log.info("param:{}", gson.toJson(insertParam);

有了這些基礎,那麼只需要有一個入口類模擬 springboot 啓動的加載,然後再映射一下 API 網關過來入口參數,即可實現 springboot 在雲函數上部署(其實就是上面 SCF 類的超級 plus 版本)。

** API 網關配置**

這裏的路徑參數對應 springboot 裏的 mapping 路徑

本地調試

有了上面那些 demo 後,可得知我們模擬雲端部署運行已經不是問題。那麼怎麼在本地調試呢?答案很簡單,直接啓動 springboot 然後調正常就完事了。

沒錯,就是直接用原生的 springboot 玩法即可。把 springboot 部署到雲函數其實就是外掛了一個 springboot 的啓動類(設計模式上叫適配器模式?(+_+)?

功能

完整的 springboot,能用 springboot 做的都能實現,我只是編寫了一些小功能驗證這個應用。

  • [x] 與本地服務器數據庫連接
  • [x] 雲數據庫連接
  • [x] vpc數據庫連接
  • [x] 外部接口調用(發短信驗證碼)
  • [x] 實現簡單的訂單流 (crud)
  • [x] 實現簡單的登錄能力
  • [x] 實現簡單的數據驗證能力

整個項目功能簡單但代碼卻不少。

安全

首先 "serverless"、"騰訊"、"雲服務" 這幾個詞就足以代表安全了,但爲了功能完整性我還是嘗試加了點東西。

在這個系統中,我選擇了 header 中加簽名的方式驗證數據,原因是啥,操作簡單,有效唄。加密手段和方案暫且不說,就從流程上來看,是很方便的:

  1. 從 API 網關調用參數中獲取到 header,body
  2. 驗證數據有效性
  3. 請求轉入業務模塊
  4. 驗證數據有效性
  5. 參數進入功能模塊
  6. 驗證數據有效性
  7. ………………

其實只有 123 步驟是最有效的,後面的 45678 如果你想的話……更不用說 API 網關本身提供的鑑權功能了。

性能

內存的話對於訂單系統來說單次請求加上 JVM 也才 300mb,而云函數單個函數執行內存能拉到 3GB,哪怕有點量的分佈式計算應該問題也不大。

併發的話雲函數上的預置併發上限 200 個,訂單系統嘛,QPS1000?10000?100000? ezpz了,再怎麼也比自家機櫃服務器強幾百幾千個量級了。

內存算力不夠服務器擴容?不存在的。

最後

生成個 VUE 項目,改改鏈接調調頁面,然後上傳到存儲桶上,一鍵打開 CDN ( ̄▽ ̄)*完美!

察覺到了到了科技的進步,時代的發展,Serverless 的強大。

One More Thing

立即體驗騰訊雲 Serverless Demo,領取 Serverless 新用戶禮包 👉 serverless/start

歡迎訪問:Serverless 中文網

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章