一、背景介紹
(一)課程預覽

Ø What?
基于Spring boot 架構 + Cassandra資料庫,實作一個支援海量使用者 的使用者管理系統。
Ø Why?
Spring Boot大幅簡化了應用搭建和開發的成本,Cassandra作為開源分布式資料庫,既具備NoSQL資料庫高性能,高可用,海量無限擴充的特點,又具備類似關系型資料庫的資料模型,非常适合開發線上應用。
Ø Who?
Web開發入門者,希望深入了解Cassandra設計和使用的使用者。
Ø How?
本文将從設計開始,手把手教使用者實作一個使用者管理系統
(二)Spring Data for Cassandra簡介
1.Cassandra
- 去中心化,海量資料擴充能力;
- Zero Down Time;
- 支援二級索引,物化視圖,集合等實用功能;
- 被Apple,Netflix,360,華為等大公司廣泛采用。
2.Spring Data
- 強大的存儲庫和靈活的抽象映射;
- 便于與Spring MVC controller 內建;
- 支援MySQL,Redis,Redis,ES,Cassandra等資料庫。
3.Spring Data for Cassandra
- 降低CQL語言的學習成本,提升開發速度;
- 支援同步,反應式和異步等多種模式;
- 支援使用者自定義複雜查詢;
- 一套代碼支援MySQL冷熱分離,ES加速查詢,Redis緩存等多種玩法。
(三)準備工作
準備工作主要分為以下三個步驟:
1. 購買Cassandra叢集
1)購買Cassandra雲服務
2)使用者密碼:雲Cassandra控制台-> 叢集詳情->賬号管理頁面
3)連結URL:在資料庫連接配接頁面
2. 配置叢集
1) 雲Cassandra控制台 -> 叢集詳情-> 資料庫連接配接頁面開通公網連結
2) 雲Cassandra控制台-> 叢集詳情-> 資料安全頁面配置本機IP到白名單
3. 配置開發環境
1)下載下傳并安裝Idea開發環境
2)在Spring模版生成器中生成項目模版
位址:
https://start.spring.io/3)将生成好的項目導入Idea
當完成上述步驟後,使用者可以獲得一個工程,如下所示:
這個工程是空的,裡面隻有一個Main函數可以執行,其他功能需要後續操作進行添加。
二、系統設計
(一)需求分析
需求分析主要分為三部分:資料需求、功能需求和其他需求。
1.資料需求
由于要做的是使用者管理系統,使用者的資料存儲在Cassandra資料庫中。使用者資料可分為以下幾個屬性:使用者ID、使用者名、密碼與使用者年齡,後續可根據需求擴充更多使用者資訊,例如email,電話号碼,住址等。
2.功能需求
功能一般分為增删改查4個部分。
增指的是在系統中增加一個新的使用者,删指的是把使用者資訊删除,改指的是修改使用者資訊,查則較為複雜。查詢可以包含很多場景,例如基于使用者ID查詢,基于使用者年齡查詢,或者要展示全部使用者的資訊。
3.其他需求
除了上述基本功能需求外,還需要注意以下四點:
1)高并發高性能
使用者可能會頻繁更新同一條資料,或者系統需要支撐100萬個使用者同時注冊的場景,或者當有1億個使用者的時候,能不能快速展示全部使用者,以上都屬于高并發高性能場景。
2)可擴充性
系統功能在設計初期,可能有一些地方沒有考慮到,例如初期沒有設計通過電子郵箱位址搜尋使用者的功能,後續有需求需要添加這個功能,是以對可擴充性有一定的要求。
3)開發靈活
系統最開始的功能可能開發起來并不會特别複雜,但随着系統的累加,功能會越來越複雜,是以需要注意開發靈活性。
4)美觀
該系統作為外部服務,會存在與使用者互動的界面,是以希望這個界面對使用者足夠友好。
(二)Schema設計
需求完成後,我們接下來需要做的事情是設計一個Schema。
這裡需要注意,一定要先完成Schema的設然後再去實作功能,否則可能會導緻系統性能會出現一些瓶頸。
分析剛才的資料,由于ID字段是唯一的,是以可以把ID字段放在主鍵的位置。
主鍵有幾個要求,首先要符合使用者查詢常見次元,例如上方提到的使用者查詢,有可能通過使用者ID、年齡等資訊進行查詢。
将ID作為主鍵而不是年齡的原因在于,一方面是年齡的區分度不夠,很多使用者擁有同樣的年齡,如果以年齡做主鍵的話,可能會導緻相同年齡的資料很多,必然要年齡後面再結合一個其他字段去保證主鍵的唯一。
其次,年齡作為主鍵可能會存在熱點問題,比如所有的使用者都是20~25歲,那麼資料都會集中在分片,導緻分片非常不均勻。
那麼,把ID放在主鍵是不是就可以解決這些問題了呢?
這要看ID本身是否足夠打散,如果是随機生成一些ID,則資料本身非常均勻。如果ID是自增的,這對于Cassandra來說并不是一個特别好的選擇。對于Cassandra的ID,我們希望盡可能去打散。當然,如果說ID把它放在Partition Key的話,因為它本身是有一些哈希可以去做打散的,是以也是可行的。
但是如果把ID放在Partition Key的話,Partition Key本身是不做排序,是以想查詢ID在5~100範圍内的所有使用者,這個查詢無法實作。由于這次的系統設計較為簡易,沒有排序的要求,是以設計當中沒有包含這項功能。
除此之外,有一個基于age字段做查詢,age字段不在主鍵中出現。如果現在不對它建一個二級索引,它本身會轉化成一個過濾邏輯,類似于全表掃描,如果資料量較小則沒有問題。由于設計的目标是一個較大的使用者管理系統,資料存儲可能是幾千萬條甚至幾億條,在這些資料當中過濾出來年齡符合一定要求的存在一定難度,是以建一個二級索引加速查詢。
建立二級索引的DDL如下所示:
(三)CQL設計
CQL設計遵循增删改查原則,實作方式如下。
1.增
insert into test_keyspace.user(id, age, username, password) values(20, 18,'apple','banana');
2.删
可以根據具體id進行删除,如:
delete from test_keyspace.user where id=20;
3.改
更改分為兩個部分,第一部分是更改的字段,第二部分是更改的資料,如要把id為2的使用者年齡改為20,則實作語句如下:
update test_keyspace.user set age=20 where id=2;
4.查
查詢分為多個方式,如果查詢所有資料,則:
select * from test_keyspace.user ;
如果根據ID查詢,例如id為2的使用者:
select * from test_keyspace.user where id=2 ;
如果根據年齡查詢,例如年齡為2的使用者:
select * from test_keyspace.user where age=2 ;
如果資料量少,不需要二級索引,通過年齡進行過濾查詢:
select * from test_keyspace.user where age=2 allow filtering ;
n 此處必須加上allow filtering屬性,否則Cassandra可能會拒絕查詢。
三、編碼實戰
(一)代碼架構
Ø 架構主要由以下幾個部分構成:
1)UserController:控制層,負責與前段互動,頁面跳轉
2)UserService:業務層,負責處理業務邏輯
3)User Repo:DAO層,負責通路資料庫擷取資料
4)CassandraConfig:存儲Cassandra叢集的通路配置
5)Resource:前端頁面位置
整個代碼按照MVC的設計分成數個子產品。前端子產品會提供三個網頁,一個是list.html,用來展示User;第二個是userAdd.html,增加一個user;最後一個是userEdit.html,表示更新一個user。
所有的html會把請求發到控制層和前端做互動,包括擷取資料發到前端做展示,跳轉到某個頁面,這些都是在控制層進行。
控制層下面是業務層,傳統的業務層更多的是處理一些業務的請求。我們這次的系統相對簡單,業務層主要承擔的作用是把DAO層的資料傳回給上面的控制層。同時,業務層也會做一些簡單的處理,比如統計一些使用者的數目,然後将這些資訊發給控制層。
最下面是DAO層,可以跟Cassandra做一一映射,負責Cassandra資料庫的通路和連結。
(二)增删改查
1.Cassandra通路配置
在通路Cassandra之前,首先要進行通路配置。CassandraConfig本身就是在Spring Data架構裡,需要繼承AbstractCassandraConfiguration去定義需要的資訊。
這裡面包括了hostList,即資料庫的連接配接串,這些資訊可以在Cassandra管理頁面找到。
第二個是keyspaceName,即通路的keyspace的具體名字。
第三個就是通路的使用者名和密碼,做權限的驗證。
最後一個是datacenter,它其實也可以在雲控制台裡面去找到。在雲控制台上它叫資料中心ID,不叫資料中心名稱,通常情況是一個CN開頭的字元串。
值得一提的是底下會有一個cassandraSession實作,它發送使用者名和密碼幫助Cassandra連接配接。
2.DAO層
Ø 定義User對象,并指定id對應user表的PrimaryKey
完成配置後開始定義資料。剛才存的是User,這個類對應到Cassandra當中是Table表,它有4個字段,分别是ID,UserName,Password和Age。這裡面有一個@PrimaryKey的定義,作用是告知Cassandra架構,ID字段是一個PrimaryKey,它是一個BIGINT。除此之外,這個實體實作了一些簡單的Get和Set的方法。
Ø DAO層隻需要繼承CassandraRepository即可實作基本的增删改查,對于帶條件的增删改查通過@Query的方式支援。
如何把實體對象真正的去與Cassandra進行讀取?對于DAO層,Spring Data也做了很多事情。
如上圖所示,CassandraRepository實作了很多基本的Cassandra通路,比如findAll是擷取一張表裡所有的資料,findAllById是可以通過ID擷取一個資料,insert是插入一條資料。有了這些之後,可以實作基本的增删改操作。
如果想實作的查詢比較複雜,例如基于年齡做查詢,可以做一個新的interface,讓userRepository繼承CassandraRepository,在裡面定義一種新的查詢叫findByAge。Spring Data支援@Query關鍵詞,它定義了要通路的資料。
3.Service層
Ø 通過AutoWired标記連結DAU層;
Ø 本例子中業務邏輯比較簡單,并未包括複雜的處理,實際開發過程中Service中可以處理複雜業務邏輯。
這裡有幾個需要關注的點:
第一個是類本身為@Service關鍵詞進行标記。第二個是AutoWired屬性,可以将UserRepository和Service層連結。第三個是實作了getUserNum,可以去userRepository拿到所有的資料,然後調size。
4.Controller層
Ø @RequestMapping來映射請求,也就是通過它來指定控制器 可以處理哪些URL請求, 函數傳回值标記跳轉的頁面位址;
Ø 傳回值通過model.addAttribute傳回前端。
(三)前端頁面
前端頁面的實作代碼可在GitHub上檢視。
左下角的add按鍵可以添加新使用者,後右上角的Edit和Delete,可以對使用者進行修改與删除。下方的搜尋使用者功能,可以根據年齡搜尋使用者。
四、總結
(一)功能示範
1.前端頁面
2.添加使用者
3.修改使用者
4.按年齡搜尋使用者
(二)示範總結
通過上述講解與示範,可以總結出設計系統主要有以下步驟組成:
1. 明确需求
- 需要存儲什麼資料
- 需要什麼查詢語句
2. 設計表結構
- 主鍵設計
- 二級索引
3. MVC實作
- 基于Model實作控制器
- 實作前端展示
n 進階思考:
1)系統需要處理高并發,如這是一個使用者點選統計,有一列是點選次數,如何能統計出使用者點選的精确次數?
2)如果該使用者系統需要支援100w tps/qps每秒,應該如何繼續疊代?
(三)更多進階功能 - Serverless Cassandra
阿裡雲推出了一個新的服務叫Serverless Cassandra,核心是解決使用者的資源管理成本和穩定性問題。
傳統模式存在幾個問題:
第一,可能使用者的服務本身體量很小,如果購買資料庫服務的話,起步門檻較高,成本對于使用者來說不太友好。
第二,如果在使用Cassandra的過程中,使用者的網站做大了,此時傳統資料庫需要不停地運維和規劃,需要通過人為觸發來擴充資料庫。
第三,傳統資源管理的方式需要提前規劃資源,可能造成較大的資源浪費。例如使用者的服務在晚上請求量較低,但在配置時需要按照高請求量場景進行配置,成本較高。
Serverless Cassandra無需任何資料庫管理,執行個體運作于龐大的資源池 ,按使用量計費,如用電一般,随取随用,适用于不頻發的、間歇性的或不可預測的工作負載。
Ø Serverless Cassandra适用場景
1)變化或不可預測的工作負載
2)定時處理任務的場景
3)新上線應用
4)完全免運維的使用者
Ø Serverless Cassandra三大特性
1)簡單易用
全托管,無需資料庫管理;
開源标準接口,應用0 改造;
豐富生态和周邊工具配套
2)經濟高效
超低門檻
存儲計算獨立計費
按使用量計費
多存儲/ 可用性級别
3)按需彈性
存儲計算獨立伸縮
無需容量規劃,自動伸縮