【架構入門系列】從業務到平臺的思惟轉變

一個需求:抽獎系統

若是你接到了一個開發需求:開發一個抽獎活動的後臺系統。第一反應若是是打開IDEA,新建一個項目,輸入項目名:lottery。而後開始根據需求着手開始進行設計數據庫,api,而後進行開發,這是太日常不過的開發流程。前端

過了一段時間,你又接到一個相似的需求:開發另外一個抽獎活動的後臺系統,可是裏面的一些業務邏輯、流程處理不太同樣,而後就把前一個完成的後臺系統複製過來,準備開始修改。git

是時候中止這種看起來很高效但實際上很愚蠢的開發方式了!本文將告訴你如何將你的思想轉變過來,給你一個將業務、將系統、甚至將本身昇華的機會。我會用偏後端的思惟、儘可能易懂的圖文、儘可能精簡的代碼、儘可能多的例子來將你的等級從熟練的業務馴服者提高爲初階架構獵人github

反思:作錯了什麼

使用複製、粘貼、修改的方法去開發一個相似的新的業務系統,從開發單個系統上來看開發效率上確實挺高的,但仍然存在如下問題:web

  • 代碼複用性低。相似的業務系統可能愈來愈多,複製粘貼致使代碼的重複率過高,可複用性過低
  • 測試、部署效率過低。須要當作一個新的後臺服務新建一套測試、構建、部署、發佈流程並進行實施,對一些通用的業務邏輯進行了重複的測試,構建發佈流程也須要單獨管理
  • 收集數據難度大。相似的業務系統的數據被分散在不一樣的數據庫、日誌中,若是想收集彙總分析一些通用的業務日誌難度大
  • 業務系統太過私有化,沒法提供相似SAAS服務那樣讓任何人都能建立本身的抽獎活動

簡而言之,老鼠的視力不好,它沒有辦法看到遠處的事物,可是咱們爲了往後業務系統的重複利用,就須要儘可能避免鼠目寸光的重複開發。算法

因此,須要將業務系統抽象爲業務平臺,支持通用的業務流程,讓業務平臺爲往後的相似的業務系統提供靈活多變的基礎業務實現方案,至於特殊的業務流程就單獨開發一個特殊的業務系統,二者共同結合提供完整的服務。數據庫

另外,平臺的使用者應該相似SAAS,具有爲全部人服務的能力,提供給能讓每一個用戶甚至每一個組織都能建立屬於本身的獨有環境,能夠經過在平臺上的簡單配置構建出屬於個體的服務。後端

如圖所示,業務系統與業務平臺共同爲用戶服務。業務平臺包含某個業務的通用流程,可能恰好能知足業務的全部需求,那麼此時就不須要另外開發一個業務系統。但若是有一些比較特殊的業務流程或者必須單首創建一個業務方便管理控制的流程的話,那麼能夠將該業務系統與業務平臺結合到一塊兒使用,業務系統提供定製接口,業務平臺提供通用接口,業務系統也能經過受權的調用接口來調用業務平臺獲取、修改數據。api

通用業務

首先咱們須要想清楚,如何從平臺的角度考慮,將設計業務邏輯才能比較通用?如何區分是否爲通用的業務邏輯,從而進行業務拆分?緩存

通用性

目的:解決業務實現的N種可能。在業務平臺上儘可能支持多的、通用的業務邏輯。安全

如何解決:把眼光放長遠一些,咱們這個業務系統如今須要支持哪些業務邏輯?往後須要支持哪些?而後進行有選擇的取捨,不須要考慮太多,不然系統將被設計的特別複雜且用到的部分太少。一個簡單有效的方法就是參照之前作過的系統和當前須要實現的系統,將通用的邏輯抽取出來。

舉幾個例子:

  • 在業務流程上的考量。好比上個活動只開了一天,獎品也都相同,可是此次的活動須要開兩場,每場的獎品可能不同。因此咱們能抽象出:一個抽獎活動可能存在多個活動場次,每一個場次對應的獎品、時間可能都不一樣,還須要支持隨時進行修改,這就將活動拆分爲活動與場次兩個層次。因此在數據庫設計的時候就須要添加一個字段來對應場次這個維度
  • 在數據庫表字段上的考量。獎品的兌換方式多是經過快遞發送實物獎品、直接展現兌換碼,因此對於表字段的種類要考慮多一些,好比須要保存用戶的收貨地址、聯繫方式。在單個字段的屬性選擇也要適當考慮可擴展一些,好比字段長度、字段類型

邊界處理、業務拆分

這裏的邊界指的是業務拆分時的邊界,好比,哪些屬於平臺通用邏輯?就能把這些通用邏輯放到平臺裏。哪些屬於業務特有邏輯?這些邏輯就不須要加到平臺裏。

好比,對於抽獎活動,配置獎品、分發獎品是抽獎平臺通用邏輯,但用戶排行榜則不夠通用,除了遊戲相關的場景,不多須要用到排行榜的功能,那麼排行榜功能就應該屬於業務特有邏輯。

在整個抽獎的業務流程中,還有一個業務流程是當抽獎次數用光,就能夠經過分享的方式增長抽獎次數。因此抽獎業務通用邏輯依然能夠繼續拆分,對於分享功能,是不屬於抽獎平臺通用邏輯的,那麼能夠將分享功能也單獨抽出來成爲分享平臺,使之也能服務於其餘的平臺或業務系統。

看似當前已經拆得比較清晰了,但尚未結束,由於這是僅僅針對於【分享成功->增長一次抽獎機會】這樣的流程,若是須要分享屢次才能增長一次機會呢?若是分享以後每次增長不一樣的抽獎機會呢?誰負責維護【分享-增長機會】這個獎勵機制呢?這就須要一個引擎、流程控制中心來處理,不如就叫任務調度平臺

任務調度平臺的核心業務流程是【完成任務-觸發獎勵】,至因而誰完成的任務,觸發誰的獎勵對它來講並不重要。只要它可以將任務的觸發者與被觸發者的對應關係、觸發條件、被觸發者的獎勵接口調用方式維護在內部,當檢測到觸發者達到了觸發條件,可以調用到對應的獎勵便可

數據處理

大數據量的存儲

既然是平臺,會由於使用者使用時長、數據量方面就會比通常的特有業務系統多,在設計時須要考慮到提早爲書數據量較大的某些表進行水平分表設計,貼一個簡單的分表的例子:

在建立數據庫時按上圖進行建立,在代碼中進行增刪改查時用下面的方法根據分表字段(shard key)來獲取表名:

func GetTableNameByActivityId(activityId int64) string {
	if activityId > 0 {
		return "activity_prize_redeem_" + strconv.FormatInt(activityId % 16, 10)
	}
	return "activity_prize_redeem"
}
複製代碼

分表時,根據哪一個字段(shard key)進行分表也是須要考慮的,須要使數據可以均衡的分佈在多張表中,而且不影響正常的查詢,這樣才能經過分表的方式將數據均勻分佈到不一樣的表中,根據shard key進行查詢時效率與不分表時同樣,但若是使用另外的一個字段查詢數據可能須要遍歷全部的表才能將數據查詢到,因此shard key的選擇是與業務查詢需求、數據均勻分佈相關。

分表以後,最直接的影響是開發的時候須要對SQL語句進行動態調整,某些ORM框架不支持致使的開發效率下降,可是改動的代碼很少,一勞永逸。

高性能查詢

對於平臺來講,併發訪問量也可能較大,那麼緩存、隊列、ES必不可少。

對於緩存,如今基本上說的都是使用Redis,可使用的集羣模式有主從、哨兵、集羣。使用的策略也有延遲加載、直寫,還須要考慮到一些擊穿、失效的緩存問題,具體能夠看這裏

對於消息隊列,在業務解耦、流量削峯方面是一個很是重要的中間件,具體能夠看這裏

對於Elastic Search,若是業務上有全文檢索的需求就是要結合EFK一塊兒上的一個模塊,具體使用方式、場景請自行查閱。

運營埋點、報表

數據過重要了!分析用戶行爲,預測市場走向,仍是之後設計系統的參考指標,咱們做爲技術開發人員,也須要爲運營人員着想,須要統計出運營人員感興趣的一些數據,最好是直接找他們提早詢問清楚,哪些數據他們須要,以便咱們在設計數據庫的時候將一些關鍵數據用一些字段保存下來。

好比在抽獎活動中,運營人員須要知道web平臺、安卓平臺、IOS平臺分別參與抽獎的人分別有多少,可是設計出來的數據庫字段、代碼中打印出的日誌可能都不存在或者難以經過現有設計進行統計,那麼就須要對這個統計需求進行單獨的設計。

日誌、操做記錄表

在代碼中輸出日誌是必須的,好比一般須要在訪問API、某個API裏的關鍵邏輯、結合關鍵數據打印成功或失敗信息。

另外,對於某些業務場景須要嚴格統計數據操做以前的狀況、操做以後的狀況、操做類型、操做人員、操做時間。雖然也能夠經過輸出日誌的方式,但不夠規範,查詢統計難度大,容易丟失。因此須要單獨設計出一張操做流水錶,將重要信息持久化起來。

在每一個須要統計的重要操做執行以後,使用消息隊列或者另外的線程去插入一條操做記錄到這張表中,以下

go service.Record(&models.SysOperateRecord{
	BizType:     dao.BizType_Customer,
	OperType:    dao.OperType_INSERT,
	OperContent: fmt.Sprintf("batch insert one new customer: %s", customer),
	Operator:    userinfo.Id,
	CreateTime:  currentTime,
	UpdateTime:  currentTime,
})
複製代碼

平臺管理

類SAAS獨立環境

如何讓用戶有本身的獨立環境?讓他們能夠在平臺上簡單配置以後建立本身的應用?

其實很是簡單,在只考慮用戶而不是租戶的命名空間下,在系統層面和數據庫設計層面多進行一層考慮便可,好比在數據庫的主表/主實體上增長兩個字段:namespace_idapp_id

  • namespace_id表明一個用戶擁有的惟一且與其餘用戶相互隔離的命名空間。一個用戶建立的全部業務系統、數據都在一個namespace_id下面,因此該用戶建立的全部業務系統的數據都能用namespace_id查詢獲得。
  • app_id表明具體的某個業務系統(應用)的惟一id。因此該用戶建立的某個特定的業務系統的數據能用app_id查詢到。

多平臺統一管理

在多個平臺(抽獎、分享、任務平臺)創建起以後,須要一個後臺管理平臺將這幾個平臺統一管理起來,方便爲用戶提供統一的配置。

以建立一個業務系統爲例,若是使用管理平臺進行配置,那麼用戶只須要在管理平臺上填寫不一樣平臺的對應業務配置便可,在管理平臺中將自動處理:

  1. 管理平臺的建立應用功能將先建立一個統一的namespace_id、app_id
  2. 將namespace_id、app_id、不一樣平臺的對應配置經過內部調用寫入到對應平臺的數據庫配置表中

對配置好平臺配置進行修改、刪除,對業務數據進行統計的操做可經過管理平臺的調整配置、統計數據接口進行

技術選型

微服務

爲何說適合用微服務架構來開發平臺?

  • 平臺業務的擴張。往平臺的方向考慮,業務邏輯會愈來愈複雜,代碼量會愈來愈龐大,爲了服務的獨立部署測試、調整,服務的拆分紅爲必然。
  • 平臺的統一管理。經過API網關、配置中心、服務發現註冊中心、熔斷器等組件,能夠將多個服務統一管理起來。好比在網關添加鑑權模塊、收集全部請求日誌,在配置中心統一管理服務的配置文件,在熔斷器中對不一樣服務進行管理配置。以上都是爲了將零散的服務經過相關組件統一成總體

業務決定架構

業務如何決定架構?

  • 業務的併發量、穩定性。若是併發量是業務須要知足的一個條件,則須要可以支撐大量請求的高可用架構。好比每一個服務節點的多節點負載均衡、數據庫使用MySQL仍是MongoDB的選擇、數據庫架構的主從複製讀寫分離、中間件的選擇、前端的緩存與CDN技術
  • 業務的第三方支持。如推送、搜索功能本身實現的話比較麻煩,通常使用第三方服務,這種第三方與本身服務的結合也是架構中的體現
  • 業務需求引起的內部交互。如通常應用的註冊功能,都會使用消息隊列這個中間件將寫數據庫行爲與其餘行爲(發短信、發郵件)解耦;還可能設計一些定時任務從某些數據源按期獲取數據更新到另外一個數據源

這裏給出另外一個比較能體現業務決定架構思想的一篇實例文章參考

性能

若是隻考慮性能,那麼不能選擇微服務架構,由於單體應用在性能上是徹底碾壓微服務架構的。若是爲了全局考慮以後仍是得選擇微服務,那麼如何在使用微服務的狀況下儘可能提高訪問的性能呢?

首先須要經過壓測的方式測試出性能的瓶頸在哪裏,這篇文章可能有所幫助。

至少須要保證能在性能問題發生以後可以當即解決,因此至少要作到服務可以在任意時刻可以版本回滾、可以動態擴展到更多機器上。而後經過對應的方式如優化代碼、使用緩存、隊列、添加服務器、改進中間件架構的方式去解決性能問題。

部署方式

對一個架構師來說,代碼從提交到上線也須要考慮到,甚至須要考慮爲團隊構建DevOps體系。簡單來講,使用自動化流水線將代碼提交、測試、構建、部署自動化起來,並在項目上線的過程當中協助開發測試運維進行代碼版本的切換、部署方式的實踐。

爲了往後服務的藍綠部署、回滾、動態伸縮,必須使用容器技術如Docker與容器編排平臺如K8S來實現。至於具體的搭建方式、維護細節不用徹底掌握,但必定要知道各類部署方式、服務維護方式和其利弊。

安全考慮

業務安全

對於抽獎系統,由於獎品有實際價值,因此直接跟錢掛鉤。爲了防止惡意用戶擼羊毛,必須對可能存在的抽獎後門進行封殺。

對於抽獎系統,最大的後門是:中獎接口。如何判斷用戶是真正的玩了這個遊戲並一路闖關達到終點奪得獎勵的呢?對於web平臺來講真的是一個比較困難的問題,由於沒辦法跟遊戲同樣實時得到用戶的數據進行詳細的斷定,因此只能在最大程度上增長中獎接口的校驗規則。以下:

  • 遊戲邏輯校驗。根據前端設計,先測試出奪得獎品最快用時是多少,而後在後臺加入判斷:若是用時少於最快用時,封殺。另外能夠根據遊戲業務邏輯判斷:必須經過點擊【贊成協議】、【開始遊戲】這兩個按鈕(訪問這兩個接口)才能成功調用中獎接口。
  • 驗證碼。防止惡意用戶使用腳本自動刷獎,中獎接口添加驗證碼方式校驗。但這極大程度上影響用的體驗,謹慎使用。
  • 黑名單控制。對於反覆調用不少次的用戶,直接將該用戶id加入到黑名單中,在一段時間內禁止接口訪問。

網站安全

這是一些比較通用的web安全問題,通常在框架內部已經解決,但也須要確認是否開啓相關安全機制。

  • SQL注入。若是使用的是ORM框架則不須要擔憂這個問題,由於框架內部已經使用轉義的方式幫你處理好會影響SQL語句的特殊字符。若是涉及到複雜的SQL手動拼接,那麼必須在開發時使用佔位符的方式來拼接字符串來解決該問題
  • csrf。像Go語言的Beego框架,Ruby語言的Ruby On Rails框架,Java語言的Spring Security中就已經提供解決方案,但並非默認開啓,須要在先後端統一配置才能生效,後端配置以後,會在session存儲一個csrf的token,等待下次請求前端傳過來這個token來驗證。因此對於某些安全性較高的操做是須要添加csrf防範的
  • xss。在框架裏可能沒有現成方案,那麼須要在先後端都加以防範,好比在前端JS中要避免把不可信的數據看成代碼執行了,在後端須要配置專門的過濾器,在過濾器中使用轉義工具將影響JS執行的特殊字符進行轉義
  • https。防止中間人攻擊,提高網站安全性、搜索權重,衆人皆知,再也不贅述
  • 權限控制。避免普通用戶可以使用管理員的權限相似的問題,須要在後端進行限制
  • 密碼管理。即便數據庫被人破解,也不能讓別人看到你的明文密碼。對於不須要解密的密碼,好比用戶登陸的密碼,使用bcrypt算法或md5加鹽進行加密;對於須要解密的密碼,使用AES或對稱加密算法加密保存,加解密使用的密鑰須要另外保存

等等等等,網站安全問題是在太多,沒辦法都寫出來,不過以上問題比較常見,須要在開發時外加註意,這些雖然不會在架構設計圖上展現出來,可是會是一個存在的架構隱患

總結

咱們從業務、數據、技術、安全方面綜合考慮如何將簡單的業務設計成爲一個平臺,看重的是長遠的收益,提高的是本身的能力。做爲開發人員的你也許已經煩透寫業務代碼,不妨換一種開發思想挑戰一下本身吧。

來源:91Code

關注公衆號獲取更多內容!

在這裏插入圖片描述
相關文章
相關標籤/搜索