高效能的連線管理和資料路由元件,OceanBase 生態工具 ODP 詳解
作者簡介:致新,OceanBase 資料鏈路高階研發工程師。
一、ODP 簡介
1.1 OceanBase 生態
OceanBase 除了核心中大家相對熟悉的 SQL 模組、事務模組、儲存模組等,其周邊還有很多生態工具來幫助 OceanBase 服務好使用者,比如本章將要介紹的 ODP(原名是OBProxy,現改名為 ODP)。ODP 是 OceanBase 的訪問入口,具有代理和中介軟體的特性。
1.2 ODP 發展歷史
ODP 目前的產品特性,除了方案設計外,和產品的發展歷史也有關,介紹 ODP 發展歷史可以幫助大家更好的理解 ODP 的產品特性。
ODP 的歷史主要分成了三個階段:
- 2014-2018:ODP是和OBServer核心一起開發的,伴隨著 OceanBase 核心一起發版,最開始的目的就是幫助使用者更好地去訪問 OceanBase 。
- 2018-2021:在螞蟻內部,ODP 轉交給中介軟體團隊,增加中介軟體和雲原生能力。
- 2021-至今:在 OceanBase 去年成立公司後,ODP 團隊又從中介軟體回到了 OceanBase 團隊,目前隨著 OceanBase 的商業化和開源一起服務更多的使用者,目前在開發更多的能力支援,也在完善相應的產品化能力。
1.3 訪問入口
ODP 是什麼?簡單來說,ODP 是資料庫的訪問入口,OceanBase 的定位是一個分散式資料庫,ODP 讓使用者更簡單地訪問資料庫。
舉個例子,我們應用命令列登入 MySQL、Oracle 等產品時,需要指定 IP、port、使用者名稱和密碼,而對於分散式資料庫 OceanBase 來說,這裡存在的問題是如果同時存在三臺 OBServer 時如何填寫這些資訊。ODP 讓這一切都變得簡單,使用者使用時只需要填寫 ODP 的 IP 和 port ,就可以正常訪問資料庫。
ODP 完全相容 MySQL 協議,目前主要是 5x 系列版本協議,8.0 協議還在適配中。因為協議相容,所以使用者的程式碼可以使用現有的 MySQL 語言客戶端,如 Java 程式可以直接使用 MySQL 的 jdbc 實現。對於訪問資料庫的程式碼,使用 ODP 時只需要修改 IP 和 port,其他的程式碼無需做任何改動就可以訪問 OceanBase 資料庫。
ODP 作為入口的效能是非常好的,支援多執行緒利用多核能力、實現非同步程式設計提供高效轉發,不會有阻塞操作。ODP 本身非常輕量,無狀態不會存取資料,擴充套件性好。
上圖說明了一條 SQL 的訪問路徑,下面的三個 zone 可以簡單地理解成機房,一個機房裡部署了兩臺 OBServer,資料分散在所有的 zone 裡面。當執行一條 SQL 時,ODP 可以準確地把這個 SQL 請求傳送到有該資料的 OBServer 上。
路由方面,ODP 還支援了 OceanBase 的弱讀功能,可以實現讀寫分離,將讀流量發往備副本,實現負載均衡。
1.4 代理模式
關於代理產品的優缺點,下面是我的一些思考:
- 效能損耗。客戶端到代理之間的網路多一跳可能會影響RT和QPS。
- 代理本身負載均衡和高可用。
這裡舉兩個場景,一個是現在比較流行的 Docker、Mesh 化的部署。ODP 本身支援了 sidecar 的部署,可以理解為應用部署在一個 Docker 中,ODP 部署在另一個 Docker 中,兩個 Docker 在同一臺機器上,這樣它是一對一的關係,只需要使用者的 Docker 訪問旁邊的 ODP 的 Docker。
除了這種模式之外,還有另一種可能是集中部署。ODP 前面都會部署一個 LB 元件,如 F5,雲上也有專門的 LB 場景。
這兩種場景都比較常用,sidecar 部署目前是和雲原生一塊發展的,螞蟻內部廣泛使用這一種部署方式。LB 部署也很多,阿里公有云上的 ODP 就使用了這種部署,在私有云場景中也經常被採用。
- 部署和運維。ODP 作為一個獨立的程式,需要考慮這個程式的資源規劃以及專門的配置推送,如重啟、配置在 LB 上的相關資訊,代理模式帶來了運維的複雜性。
- 語言無關,和業務解耦合:Proxy 模式無需為每種語言開發一種驅動,減少研發成本;和業務解耦合,升級更加方便。
- SDK or Proxy。為使用者提供選擇。
1.5 架構比較
大家做架構比較時,對於單機資料庫的代理一般使用直連方式,在生產環境下可能會採用代理元件,如 ProxySQL 會做一些 MySQL 主備之間的切換。關於 OceanBase 的架構,下面和另一款比較知名的開源分散式資料庫 TiDB 去進行一些比較。
從 TiDB 的架構上大家可以看到,TiDB 本身是沒有代理產品的,LB 後面就直接是 TiDB 的 server ,在 TiDB server 後面是 TiKV。為什麼 OceanBase 就有 ODP 這個模組去做代理呢?這和 OBerver 本身的實現有關,雖然大家都是分散式架構,但也有不同。OceanBase 是單機分散式一體化的架構,目前沒有做存算分離,它的計算節點和儲存資料的節點都在一起。TiDB server是一個 SQL 處理引擎,本身是無狀態的,它將請求轉發給後面的 TiKV,是存算分離的。
TiDB server 裡面實現了路由功能,還做了語法解析、計劃生成等。ODP 就比較簡單,只實現 SQL 轉發,同時保證高效能的轉發效率。ODP 都可以保證 SQL 發往的那臺 OBServer 是有相關資料的。舉個例子,向T1表插入資料,ODP 可以保證把請求發往有 T1 表資料的機器,這樣整體效能最好。
另一方面,ODP 在訪問核心鏈路上做了各種效能的優化,可以保證不會成為整個鏈路上的瓶頸。
最後,代理產品除了為 OceanBase 路由外,它還可以去做一些中介軟體的能力,比如白名單、分庫分表等。整個產品作為獨立的元件,安裝部署非常方便。
二、ODP 特性介紹
2.1 高效能轉發
ODP 的第一個特性一定是高效能的,在網路多一跳的情況下,我們一定要保證轉發效率足夠高,不會成為系統的瓶頸。ODP 在設計實現上是多執行緒加非同步的程式設計模型。在效能測試中,我們在阿里雲 ECS.g7.8xlarge 機型上測試了 sysbench的point_selec t場景,得到了下面這組資料。大家可以看到第三列,三機部署的情況下 ODP 做到100萬的轉化只需要30個核左右,所以它的單核轉發效率是特別高的。
ODP 是怎麼實現高效能的呢?上圖簡單地介紹了 ODP 的執行緒模型。ODP 的每個執行緒基本上可以認為是一樣的,各自獨立地去做轉發任務,執行緒之間基本沒有共享資料,可以充分地利用多核的能力。
程式碼實現上有兩套邏輯,一個是 IO 邏輯,即 TCP 流的轉發;另一個是業務邏輯,進行資料轉發和處理的流程。這兩個邏輯都是在同一個執行緒裡完成的。
關於 ODP 的效能,一方面需要保證執行緒數,如果設定了 ODP 執行緒數是8,那我們最多隻能利用8哥 CPU 核。所以要合理的設定工作執行緒數。不建議設定執行緒數超過機器本身 CPU 的核數,這樣就會存在兩個或多個執行緒搶佔同一個 CPU,效能反而會下降。另一方面是我們可以保證把任務均勻地分發到每個執行緒裡,這樣做到每個核的負載均衡。
前面講到了執行緒模型和我們的測試資料。我再從程式碼優化和整體效能去說一下。程式碼層面,針對主路徑做了很多優化,提高程式執行效率。另一方面,為了保證效能不回退,我們實現了核心場景的效能迴歸。比如 TPCC 場景、螞蟻內部的核心交易支付場景等。
從整體效能來看,ODP 不追求本身的效能最優,而是保證整個鏈路的效能最優。舉例說明,來了一條 SQL 以後,一種轉發策略是簡單的把這條 SQL 轉發給一臺 OBServer ;另一種策略就是對這個 SQL 做解析,比如提取表名獲取這個表的分佈,再把 SQL 轉發給有相關資料的 OBServer 。在 ODP 層面,第二種方式相比第一種方式多了 SQL 的解析以及獲取 table、table 資料分佈的邏輯。ODP 雖然需要犧牲 CPU 去計算這套邏輯,但根據實際測試場景的表現,第二種情況的整體效能要明顯優於第一種。這就是所說的全鏈路最優。
簡單介紹一下 ODP 效能問題的分析。ODP 前面連著 LB 或業務的 App,後面連著 OBServer ,所以一定要全鏈路去分析效能問題。ODP 和 OBServer 經過很多年的場景的鍛鍊,整體的效能還是非常穩定的。當確定是 ODP 的問題時,大家可以用 top 命令或 perf 命令去檢視具體的效能。比如通過 top 命令,如果 ODP 和 OBServer 部署在一起,那麼 ODP 的 CPU消耗是要小於 OBServer 的;使用 perf 命令檢視 ODP 有沒有熱點函式,基本上 ODP 每個函式的消耗都沒有超過5%的。效能優化是很複雜的問題,需要從全域性把控。
2.2 連線管理
ODP 能夠使得訪問 OBServer 足夠簡單,首先介紹一下登入資訊和登入流程方面的內容。
OceanBase 本身的架構非常複雜,從使用者名稱就可以看出,如完整名字為 username@tenant_name#cluster_name:cluster_id,username 是連 MySQL 資料庫時的使用者名稱,tenantname 是訪問的租戶名,因為 OceanBase 本身是多租戶的,cluster_name 指定訪問的叢集。ODP 不僅可以代理同一個叢集,還可以代理多個叢集,即通過一個 ODP 不僅可以訪問一個叢集下的不同租戶,還可以訪問多個叢集下的不同租戶。cluster_id 和 OceanBase 的主備庫形態有關,比如0代表主庫,1代表備庫。
ODP 對 MySQL 協議完全相容,目前是相容的 5.7 版本,8.0 版本協議正在做相關的適配工作。基本上使用開源的 MySQL 的客戶端都可以直接訪問 ODP ,但是如果是 Oracle 模式,還是必須用 OceanBase 的專有客戶端。
最後再解釋一下 ODP 是怎麼做到可以代理不同叢集的不同租戶的。一種方式是 rslist 的方式,OceanBase 中包含一個 rootserver 元件,把 rootserver 的地址配給 ODP 就可以。但是這種方式的問題是 ODP 只能訪問一個叢集了。另一種方式就是通過 OCP 元件的 URL ,OCP 儲存不同叢集的所有的 rslist 資訊,這樣就可以訪問不同的叢集了。
OceanBase 的整個登入流程還是非常複雜的,首先進行 MySQL 協議的握手,在建立連線後客戶端會主動發一些 SQL,比如 set names UTF8 ,告訴資料庫傳輸的資料都是 UTF8 編碼的。OceanBase 比這個還要再複雜一些,因為 ODP 本身也會發一些內部的 SQL,比如查詢叢集機器列表,因為訪問每個叢集時,需要拿到這個資訊再去把這個請求轉發給對應的機器。
整個登入流程比較複雜,但一般是沒有什麼問題的。特殊場景下,比如說某條 SQL 突然執行慢了,很可能會導致登入失敗,這是本身複雜導致的。
在瞭解 ODP 的產品行為時需要從分散式角度考慮。大家使用 MySQL 時直接使用客戶端連線,只需要考慮一個連線方向。但 ODP 場景就比較複雜,上圖中的 OBProxy 是我們的 ODP程式名,對於一個客戶端的連線,目前的實現是會和 server 建立多個連線的,形成一對多的關係,此時就要考慮和客戶的連線、和 server 連線的問題。
假設分散式系統中一個 server 發生了當機、重啟等各種情況,ODP 一般都會對這各種場景會做一些相關的處理,遮蔽 server 的故障,客戶端和 ODP 的連線還是繼續保持,這樣就可以保證客戶端和 ODP 之間連線的穩定。
一個 ODP 和 OBServer 之間連線,它只屬於一個客戶端和 ODP 的連線,不會做共享複用。比如說有兩個客戶端,他同時訪問同一個 OBServer,他這時候會建兩個連線,而不是說共用同一個連線。目前我們的實現是這樣的,後續會實現連線池的功能。
最後一個再介紹一下這個狀態同步的功能。假設使用者主動發生了傳送 set autocommit=0,ODP 需要對所有的 OBServer 實現狀態同步。Set autocommit=0 這條 SQL 只會發往一臺 OBServer ,執行完成後將結果返回給客戶端。當下一次訪問另一臺 OBServer 時,需要由 ODP 保證 set autocommit=0,實現 ODP 和 OBServer 之間的狀態同步。
後面就是舉幾個問題,讓大家更深入地瞭解一下連線管理部分。
- 兩段連線的複雜性。當需要檢視當前有哪些連線時,向 ODP 傳送 show processlist 命令。此時 ODP 不能直接轉發給 OBServer ,不然只會展示一臺 OBServer 的連線情況,但使用者想看到的是所有的連線。所以這裡由 ODP 攔截這個 SQL ,統計自身有哪些連線,處理完成後返回給客戶端。 Show processlist 命令展示的是 ODP 和客戶端的連線,而不是把這個命令轉發給 OBServer 。另外比如說對於 kill session 的操作,由於有兩段連線,大家需要確定是在 kill 哪段 session 的連線。
- 連線保持。要保持住連線很困難,比如說前端的業務應用可能會斷連線,ODP 如果本身出 bug 了也會斷,OBServer 本身出問題了也有可能斷。所以整個斷連線的處理是非常的複雜的。如果想保持住這個連線,需要做很多容錯處理。比如後端 OBServer 出現異常時,ODP 會進行遮蔽處理。
- 異常、問題分析、問題排查。ODP 的問題分析比較複雜的原因就是它涉及鏈路比較多,排查問題的時候要一個鏈路、一個鏈路逐個去排查,整體難度相比直連會複雜一些。
舉例來說,如果客戶端和 ODP 的網路慢,ODP 和 OBServer 的網路是正常的,但是對於使用者的體驗都是一樣的,整個訪問都是慢的,這裡只能去分段去排查。
在實際場景中主要還是要大家都積極地配合,OBServer 提供相關的資料,客戶端本身的資料也非常的關鍵,比如執行時間以及執行的 SQL 。比如說大家用 jdbc ,jdbc 本身的超時引數可能會把連線斷掉,如果應用可以提供給我們時間點和具體的 SQL,可以幫助我們去分析問題。
再講解一下 PS 模式的實現,瞭解一下 ODP 對整個分散式狀態管理的複雜性。PS 模式直連比較簡單,第一個請求是傳送 prepare 請求,select * from T where A=?,下一個請求就是 execute 的請求,把相關資料帶回來。
ODP 需要實現最佳路由,將請求發往資料所在的機器。假設表T是分割槽表,資料分佈在多臺 OBServer 上。使用者執行第一個 execute 時,發現資料在 OBServer1 這臺機器上,就可以把 prepare 請求發給 OBServer1 機器,再傳送 execute 請求。使用者在傳送第二個 execute 請求時發現資料在 OBServer2 ,ODP 不能簡單地把這個請求發往了發往 OBServer2,一定要把之前的 prepare 請求發過去,不然就出現了 OBServer 沒有 prepare 就 execute 的情況。
2.3 超時管理
一些超時引數會影響相關的行為。
- jdbc 超時。socketTimeout 表示網路的超時時間,在螞蟻內部設定是5秒,如果出現錯誤就迅速把連線給關掉。所以會出現應用程式5秒前傳送資料後再也沒有傳送資料的情況,此時連線斷開。connectTimeout 是連線超時引數,jdbc的文件中有對這些超時引數的相關介紹。
- OBServer 本身的實現中也有一些超時引數,其中部分超時引數是 OceanBase 特有的,如 ob_query_timeout 是一條 SQL 執行的超時時間,ob_trx_timeout 是事務超時的時間。
ob_query_timeout 設定為10秒時,如果一條 SQL 在10秒後沒有執行完成,OceanBase 會返回一個錯誤。如果10秒內 OBServer 沒有給 ODP 返回這個錯誤,ODP 這時候就比較難處理。因為在10秒後,這條 SQL 要麼執行成功,要麼返回錯誤,但是現在沒有獲得任何請求。ODP 在這裡進行了相容處理,專門提供一個額外增加20秒的配置項,如果比如說10秒+20 秒後還沒有任何返回請求就會斷開連線,因為這種狀態是異常的。
- TCP 本身也有一些相關的引數,ODP 主要處理了兩個,keepalive 引數主要是探活,NO_DELAY 引數是指 TCP 採取專門的演算法快速傳送資料減少延遲。
2.4 資料路由
OceanBase 本身也是有資料路由能力的,假設T1表的資料在 OBServer1,如果這條 SQL 發往另一臺 OBServer 的話,另一臺 OBServer 會做轉發。但是目前 ODP 的轉化效能是最高的。
路由除了資料分佈以外還需要考慮更多的因素。
- 是否弱讀,如果是弱讀,不要求資料是最新,可以把這個請求發往備副本,這樣主副本的壓力就可以降下來,可以做一下負載均衡。
- server 狀態的管理和資料分佈。資料分佈指表的資料與 server 的關係。server 狀態管理指的是檢測 Server 是否發生當機或者重啟等故障。如果 ODP 把請求發往了一臺重啟中的OBServer,會導致卡住的現象,影響效能和高可用體驗,整體使用者的 QPS 下降,無法保證一個平穩的狀態。
- 路由相關的位置資訊。位置資訊是分散式系統中一個非常重要的因素,它反應的本質是延遲。如果是發生了跨城、跨州,整個請求的影響是特別大的。OBServer 本身的部署非常靈活,支援單機、雙機房三機房、兩地三機房、三地五中心等各種架構,需要考慮位置因素保證使用者體驗的。
路由因素這裡舉了三個比較重要的類,路由本身是和業務相關的,其他點暫時就不列舉了。ODP 路由的主要流程可以概括成四個情況:
- 解析 SQL,獲取庫名、表名和 hint,比如 hint 表示是否弱讀,表名指示資料分佈。
- 確定路由規則。leader 優先主要針對強讀情況,此時要求讀到最新的資料,因此需要發往 leader 所在的節點。LDC 路由是螞蟻本身的 LDC 單元化架構下的一種路由規則,本身反映的是位置資訊。對於弱讀情況,LDC 在已知位置資訊的情況下提供最近的節點,保證體驗。比如應用部署在杭州,有兩個備副本分別部署在杭州和上海,此時 LDC 路由會將請求發往杭州。
- 獲取路由表。路由表的資訊快取在 ODP 裡,確定路由規則時需要獲取路由表的資訊。簡單的非分割槽表路由一般採用1:1:1的部署,包括一個 leader 和兩個 follower ,t1表會擁有三個副本:一個主副本,兩個備副本。這樣的路由比較簡單,對於 leader 優先的情況可以直接發往主副本。
另一個是分割槽表的路由,分割槽表本身有很多的 leader 副本,需要根據使用者的 SQL算出具體的資料存放在哪個 leader 副本後才能發往正確的資料,與非分割槽表路由表相比增加了分割槽計算的步驟。
- 容災檢查:除了以正常邏輯選出 OBServer 之外,還需要做黑名單和灰名單的容災檢查。比如在路由表資訊沒有保持最新的情況下,選擇的OBServer 可能有出現當機的情況,此時必須將請求傳送到其他節點。
路由是我們 ODP 處理的最多的問題之一,因為其中的每一個流程都存在著非常複雜的情況。
- 支援的 SQL 數量和 SQL 長度有限。在做 SQL 解析時,目前 ODP 能夠支援常見的規範 SQL 語句,但並沒有支援所有的 SQL 語法,解析不了過於複雜的語句,比如說像 insert+select 同時 select 內部巢狀更多的語句,會導致無法提取表名,不知道資料分佈。
另一個問題是 parser 目前最多解析4K的資料,如果使用者寫了特別長的一個資料,比如寫了一個16K的 SQL 請求,那很可能是拿取不到的。我們目前正在完善對複雜 SQL 語句的支援,但也需要考慮與快速解析的效能的權衡。對於 SQL 長度的問題,為了提取表名很可能需要把整個 SQL 全部儲存下來才能進行分析,此時如果同時併發很多大請求,記憶體消耗會特別大。這也是我們保留目前設計的原因。
- 路由快取的更新和過期機制。快取系統的問題包括何時更新、何時過期兩個部分,ODP 目前的實現還是相對簡單,不會主動地去更新,這有一定的歷史原因。在採用雲原生後,螞蟻內部部署 ODP 的數量非常多的,大概是幾十萬個。此時如果主動更新,對 OBServer 造成的壓力會特別大。當集中部署的 ODP 數量比較少的情況下是可以考慮主動更新的,目前我們也在完善這些策略。
路由快取被動更新的另一個例子是彈性問題。比如說雙11大促的時候,突然需要爬表做副本重新分佈等操作,此時由於 ODP 快取沒有主動更新,所以需要大流量地去觸發 ODP的更新機制。ODP 雖然沒有主動更新,但是對於錯誤的路由提供了反饋機制,因此可以觸發所有表的反饋機制去完成更新操作。
此外,高可用機制下,對機器進行變更後可能會路由到不符合預期的機器,有可能就是快取資訊沒有更新。
- 路由策略。我們支援豐富的路由策略。但是隨著路由策略的豐富,路由的複雜性也在增加。其中一些路由策略和配置相關,導致管理的複雜性也增加。
- 容災。在遇到錯誤時如何快速地發現問題,並將問題機器剔除。
- 遠端計劃。OceanBase 的計劃分為三種:1. local 計劃,把請求發往有資料的節點;2. 遠端計劃,ODP 資料傳送錯誤導致 OceanBase 本身還需要進行一次路由。3. 分散式計劃。遠端計劃舉例來說,像螞蟻內部大部分場景並沒有遠端計劃,因為本地計劃執行效率最好。在實際場景中,如果產生較多遠端計劃,則需要考慮 ODP 本身的路由是否出現問題。另外,由於 ODP 最開始面向是 OLTP 場景,所以其對分散式計劃支援的相對有限。
2.5 路由快取
- 路由資訊。這一部分的主要問題在於如何識別出過期資料並更新。快取路徑型別分為兩種:1. sys 和租戶的機器列表資訊。該部分資訊與 OceanBase 的分散式架構有關,其支援多叢集,多租戶,因此需要快取 sys 和租戶的機器列表資訊。2. 表的 partition 資訊。如使用者需要從t1表中讀取資料,需要知道資料分佈的具體位置,也就是表的 partition 資訊。前者是機器分佈資訊,後者則是副本分佈資訊。
- 更新機制。瞭解更新機制有助於使用者瞭解 ODP 的一些行為。更新機制在首次訪問時為主動拉取,此後在淘汰後才進行觸發。淘汰指的是,在 OceanBase 發現遠端計劃後會將相應的快取資訊標記為過期,進行淘汰。因此,系統一般不進行主動更新,但是提供了觸發更新的運維命令,可供使用者進行主動重新整理。
- 淘汰機制。OBServer 的反饋會包含特殊的錯誤碼,比如 OB server 無法分配記憶體,路由的機器沒有租戶等錯誤的提示。
2.6 LDC 路由
ODP 可以配置 LDC 路由策略,配置後可將位置資訊與 OBServer 的狀態資訊納入考慮。
- 位置資訊和OBServer本身特性。狀態資訊非常重要:1. 每日合併會導致合併期間執行效率明顯降低,OceanBase 需要識別是否在合併的狀態,以確保不是所有的機器在同一時間點做每日合併;2. LDC 對兩種場景有明顯作用。一是在弱讀的場景下,二是在 parser 沒有識別出表名,需要從租戶的機器中進行隨機選擇,需要考慮到機器的位置資訊。
- 實現方式。LDC 即邏輯物理單元,可以將其理解為一個機房,同機房網路延遲低,跨機房的網路延遲高。由此,ODP 設定本身的 IDC 資訊指的是 ODP 先設定自己所在的機房資訊。OBServer 設定每個 zone 的相關資訊,因為 zone 中的機器不存在跨機房的可能,因此該資訊表明了所有相關機器的位置資訊。而例如機房所在的城市資訊,OBServer 中沒有設定權,需要再 OCP 中進行設定。舉例來說,如果某個應用部署在上海,應用會訪問和其在一個機器內的 ODP ,並由 ODP 將資料發往上海的 OceanBase 的 zone 中,而不會發往深圳或者杭州,從而降低 sql 的延遲,避免出現慢查詢。
2.7 Primary Zone 路由
分散式資料庫可以把資料做分割槽打散,充分利用每一臺機器的資源,但是也存在明顯的問題,如無論如何優化,分散式事務的執行效率不會高於本機的執行效率。OBServer 為了效能場景,提出了 Primary Zone 的概念。
- Primary Zone 指的是所有 leader 分佈在 Primary Zone 中,由此事務可在一臺機器進行執行,執行效能高。
- Primary Zone 路由。如果確認 OBServer 的租戶設定了 Primary Zone ,所有請求可以直接發往 Primary Zone 。另一方面,如果 ODP 不知道表名,無法找到副本的位置,則可以直接發往 Primary Zone,因為 Primary Zone 一定包含 leader,這樣處理效率最高。目前開源版本中,包括 Primary Zone 路由能力,但是仍待完善。比如該版本的 Primary Zone路由只能進行全域性設定,無法做到租戶級別。後續可以進行完善,做到自動感知、租戶級別生效。
- Primary Zone路由的缺點。Primary Zone 路由中,所有 eader 發往一臺機器,會存在負載不均衡的問題。這個問題可以通過租戶之間打散的方式進行改善。另一方面可以進行讀寫分離,不再將寫請求發往 Primary Zone。
2.8 高可用
前述兩點反應的延遲在於效能方面,另一方面是高可用的關於黑名單的處理。高可用中有30秒恢復或者45秒內恢復的說法。ODP 一方面從 OBServer 處查詢獲取資訊,另一方面通過真正執行獲取反饋資訊,建立一套複雜的重試或黑名單相關的策略來完成高可用。
2.9 專有協議
ODP 的另一個殺手鐗是協議。一方面,一般應用和 ODP 相容 MySQL ,利於生態的擴充套件。另一方面 ODP 和 OBServer 對協議做了擴充。比如在資料安全方面,可以校驗資料的 CRC 保證資料傳輸的準確性,進行 SSL 傳輸加密。能夠支援 Oracle 模式的資料型別和互動模型。從監控診斷方面來說,可以進行全鏈路監控,記錄監控資訊。在狀態同步方面,解決了 O BServer 和 ODP 之間如何高效的進行傳輸同步的問題。
2.10 中介軟體特性
ODP 支援很多中介軟體特性。
- 登入相關。ODP 支援常見的白名單和連線數的管理。
- 連線相關。ODP 支援傳輸加密。
- SQL 執行。ODP 支援限流和熔斷。
- 架構相關。ODP 支援 sharding,分庫分表。
三、ODP 實踐
3.1 安裝部署
ODP 的二進位制名為 OBproxy ,編譯後約佔 400M ,除去符號表約佔 30M,核心鏈路的函式有200多個。使用者可從原始碼進行編譯,或者通過開源的相關工具或者生產環境,通過 OCP 進行安裝部署。OBproxy 足夠輕量,對 CPU 核數沒有要求,啟動記憶體在百兆級別,在普通的 Linux 機器均可啟動。守護指令碼 obproxyd.sh 通過 Linux 的 nc 命令嘗試連線 ODP,如果埠連線不同,對 ODP 進行重新拉取,可以秒級拉取恢復高可用。
如上圖的截圖中,顯示了安裝好後,ODP 的目錄。bin 目錄存放二進位制檔案,etc 目錄存放配置檔案,log 可供使用者查詢日誌相關。
ODP 的部署有兩種方式。
- 進入客戶端進行部署。和應用是1:1的關係,減少延遲,並且排查問題相對簡單。
- 集中部署。該方式將應用的機器連線SLB,SLB在通過負載均衡將流量傳送給 ODP,ODP 再將流量傳送給 OBServer。比如在私有云的場景中,客戶不允許將 ODP 部署到應用機器,則只能採用該架構。在公有云場景中,ODP 和 OBServer 之間不能夠有 SLB ,因此只能將 ODP 放在 SLB 後,SLB 做四層負載均衡,ODP 做七層負載。ODP 本身的擴充套件或摘除非常簡單,只需要在啟動後修改配置即可。
3.2 監控
系統提供了 SQL 化的介面命令檢視 ODP 的狀態。例如,使用者可以通過 MySQL 的命令列連線管理員賬號,然後通過特定的命令檢視例如 ODP 的記憶體使用等。此外,ODP 支援普羅米修斯系統,可以將資料傳輸給普羅米修斯系統。最後,監控比較關鍵的日誌,如慢 SQL 、錯誤 SQL、SQL 統計日誌,以及 SQL 審計日誌,監控指標包括 QPS、TPS、連線數、響應時間、錯誤數等。
3.3 運維
我們提供一個管理員的賬號—— root@proxysys。連線這個賬號,請求並不會發往 OBServer ,並且整套命令和 MySQL 協議完全相容,使用者可以用 MySQL 命令列或者用 jdbc 程式來運維 ODP。
這裡介紹兩個內部賬號。第一個是運維管理員。第二個是一個 sys 租戶的域賬號,這個賬號是 ODP 訪問 OBServer 的內部資料的賬號。現在 ODP 訪問 OBServer 採用了 SQL 的介面,目前通過這個賬號來實現的。
3.4 ODP 問題分析
ODP 如果出現了問題,該如何分析?
- 系統相關
- 程式 core,不符合預期。因為 obproxyd.sh 會快速拉取,所以可能在程式 core 後,迅速被拉取了,導致使用者對此沒有感知。可以通過 dmesg 進行檢視。
- 記憶體相關。ODP 會設定一個記憶體上限,如果 ODP 使用記憶體超過上限,ODP 會主動退出並列印關鍵日誌。
- 目錄和檔案許可權的問題。比如,程式啟動不起來什麼的,可能因為之前用 root 賬號操作,後面用 admin 賬號的操作,導致的目錄和檔案許可權問題。
- 業務相關
- 登入失敗。一般該問題出現在配置不對等原因。
- 連線關閉。比如某個業務執行了幾個小時,突然間中斷了,導致該情況的原因較多,在前文連線管理中有所闡述。
- 慢 SQL。ODP 會對自身的主要環節,如路由規則列印進行耗時統計,方便定位問題。所以,需要使用者定義好慢 SQL 的閾值,由此,SQL 執行超過該閾值,ODP 就會列印詳細資訊,供後續分析。
- 錯誤 SQL。如果 SQL 執行失敗,obproxy_error.log 會記錄錯誤資訊。
3.4 ODP 日誌介紹
ODP 的日誌相對來說非常規範,基本的種類如 digest 日誌是審計,slow 日誌是慢 SQL,error 日誌是錯誤 SQL,stat 日誌是 SQL 的統計資訊。相關 SQL 的關鍵資訊在這裡簡單列舉:如時間、租戶、SQL 、錯誤碼等。
這裡介紹一下相關問題的處理思路:
- 如斷連線或 SQL 執行失敗。一般,不推薦使用者先去看主日誌,因為這個日誌比較複雜難懂。如果是 SQL 登入失敗的情況,在 error 中就會有記錄,裡面會有關鍵資訊,獲得 tracert 後再進行搜尋,這樣會高效很多。
- 對於慢 SQL ,在 obproxy_slow.log 日誌以及主日誌中搜尋關鍵字 Slow Query,包含了每一個階段的執行時間,可以檢視哪一段時間不符合預期,再進行分析。
- 如果在檢視 OceanBase 的 SQL 審計時發現 SQL audit 有個問題沒有落盤,則可以檢視 digest 日誌,可能與淘汰機制和記憶體大小有關。
- 如果使用者想要統計全量的通過 ODP 的資料,可以將 digest 的配置項改成一微秒。
該問題答案為 BC。
A 選項正確。MySQL 模式下,使用者採用 MySQL 的驅動程式即可。唯一需要注意的是,建議使用者使用5.71相關的版本,不要使用太新或者太舊的版本。
B 選項錯誤。ODP 無法保證路由 100%正確,可能會有各種各樣複雜的原因導致路有錯誤。
C 選項錯誤。如果 OBproxy 和 OBserver 之間的連線斷了,ODP 會主動地去對這種錯誤去進行容錯。但是如果客戶端與 ODP 之間的連線斷了,比如使用者在 jdbc 中設定 socket timeout 等於 5 秒,但實際的執行時間是15秒,那麼 jdbc 程式就會把 TCP 連線斷掉,此時 OBproxy 和 OBserver 的連線也不再需要,這個連線也會斷掉。
D 選項正確。
四、Q&A
- 開源版 ODP和 OBproxy 有什麼區別?這裡 ODP 支援 RDS/OceanBase/MySQL 分庫分表嗎?
這裡區別在於產品名字叫 ODP,二進位制程式的名字叫 OBproxy 。針對第二個問題,首先我們是 OceanBase 公司的產品,支援 OceanBase 的分庫分表。針對 RDS 和 MySQL 的分庫分表實現過,基本上是相容的,但是後面用得比較少,建議大家使用 OceanBase 的分庫分表。
- 場景:app->lvs->OBproxy->oceanbase。在這個場景下,app 段執行 SQL 超時了,MySQL 驅動會新建一個連線,執行 kill query thrdad_id(與 OBproxy 建立連線的時候,連線的id),將超時 SQL kill。lvs 後的 OBproxy 有多個,什麼機器保證 kill query 是正確的?兩種情況:lvs 沒有開會話保持,lvs 將新建的連線發錯到其他 OBproxy,會不會導致殺錯session?
這個場景可以理解為,比如 App 的一個 SQL 執行了 10 分鐘,它不想再執行了。但是沒有觸發 OBserver 的 query timeout,因此 SQL 還在執行,此時使用者想把這個 query 給關掉。然後 MySQL 驅動再新建一個連線,此時它這個請求很可能就會發往別的 proxy,所以這種情況下我們建議先確定這個執行很長時間 SQL 發往哪個ODP了,然後去主動避免 lvs 連線該OBproxy,再去殺死該程式。整體的操作比較複雜,因為這個新建的連線 lvs 會把請求傳送給另一個 ODP,可能會導致殺錯 session 或者很可能是一個錯誤的 session ID,然後報錯。
- 路由錯了,ODP 去更新,那能不能主動重新整理後再返回結果。不然就會有大量交易失敗,交易損失太大了。
這裡有兩種情況,首先路由會先去快取拿,如果這個快取本身是錯的,但是 ODP 不知道,還是會主動把請求根據快取去傳送,傳送以後 OBserver 才會告訴 ODP 這個快取失效了,我們會設計標記快取失效的資訊。第二種情況,如果使用者第二次 SQL 來時,因為快取資訊失效了,此時我們支援先重新整理快取,然後再去路由,然後發往仲裁機器。目前如果是 31x 版本,有個配置項去控制,如果發現路由快取錯了,可以先進行重新整理。其實大部分場景下,如果不做頻繁的擴縮容,一般不會出現這種問題。如果是做機器的運維,也建議可以先通過 SQL 在業務低峰進行重新整理,讓快取變成最新版本。
- OBServer 發生了切主,執行 SQL 會報錯,但是這個 SQL 的交易就失敗,這個影響範圍太大了。還希望能發現是這個錯就主動重新整理 locationcache。能容忍偶爾的慢 SQL,但是交易損失大了,那就不能接受了。
如果說 OBserver 發生了切主,OBserver 會進行轉發,而不會直接導致 SQL 的失敗。但如果 SQL 執行時間超過了 jdbc 的超時時間,jdbc 會主動 kill,這時才會導致 SQL 失敗。舉一個 OBserver 切主的場景,比如每日合併,對於每日合併的機器,ODP 會去做容錯,SQL 失敗需要進行詳細的分析。
- ODP 如何解決有前端 app 的全鏈路跟蹤?比如適配 skywalking。
全鏈路跟蹤,一方面需要業務方配合。比如螞蟻內部,業務 SQL中 OceanBase 只是 hint ,使用者可以寫一些自己的 hint ,傳入 tracert,獲得相關的全鏈路資訊。另一方面比如說像開源使用者或者是商業使用者,很可能得不到別的業務方的配合,所以目前我們主動去 jdbc 中進行設定,來做到全鏈路跟蹤。目前我們還沒有完全實現全鏈路跟蹤,但是相關的產品正在研發中。
最後的最後,您有任何疑問都可以通過以下方式聯絡到我們~
聯絡我們
歡迎廣大 OceanBase 愛好者、使用者和客戶隨時與我們聯絡、反饋,方式如下:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70005215/viewspace-2883557/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 教程直播第8期|一文詳解 OceanBase 社群版生態工具 ODP & OCP
- 連線池和連線數詳解
- 資料庫連線池技術詳解資料庫
- 微服務生態元件之Spring Cloud LoadBalancer詳解和原始碼分析微服務元件SpringCloud原始碼
- 微服務生態元件之Spring Cloud OpenFeign詳解和原始碼分析微服務元件SpringCloud原始碼
- OceanBase學習之路5|C 應用程式連線 OceanBase 資料庫資料庫
- OceanBase學習之路8|Java 應用程式連線 OceanBase 資料庫Java資料庫
- 多連線的資料庫管理工具Navicat Premium 16.1.5資料庫REM
- 多重連線的資料庫管理工具Navicat Premium中文資料庫REM
- Java中大資料生態和4個工具介紹Java大資料
- 更易用的OceanBase|生態工具徵文大賽正式開啟!
- Navicat Premium for Mac(多連線資料庫管理工具)REMMac資料庫
- Navicat Premium Mac(多連線資料庫管理工具)REMMac資料庫
- 多連線資料庫管理工具:Navicat Premium Mac資料庫REMMac
- 淺談資料庫發展史和 OceanBase 的誕生資料庫
- 多圖詳解 TCP 連線管理,太全了!!!TCP
- 路由器和貓怎麼連線?路由器和貓的正確連線方法教程路由器
- 詳解Redis核心資料結構和高效能原理分析(一)Redis資料結構
- JDBC 連線詳解JDBC
- 深入理解Laravel如何管理和配置多資料庫連線的Laravel資料庫
- 阿里Druid資料庫連線工具類阿里UI資料庫
- 動態路由 - OSPF 一文詳解路由
- 高效能資料訪問中介軟體 OBProxy(四):一文講透連線管理
- OceanBase 生態產品:時序資料庫CeresDB 正式釋出 1.0 版本資料庫
- 光貓下連線路由器的詳細步驟路由器
- 容器技術架構、網路和生態詳解架構
- 靜態路由和動態路由路由
- 4.2.14.4 為ODP.NET啟用快速連線故障轉移
- Laravel,PHP 如何使用資料庫連線池提高效能LaravelPHP資料庫
- 【MySQL】自定義資料庫連線池和開源資料庫連線池的使用MySql資料庫
- BDA:Hadoop生態大資料工具的漏洞掃描器Hadoop大資料
- PHP擴充套件資料庫連線引數說明詳解PHP套件資料庫
- 圖解 HTTP 連線管理圖解HTTP
- 如何使用 IDEA 資料庫工具連線 TDengine?Idea資料庫
- .Net 下高效能分表分庫元件-連線模式原理元件模式
- 詳解:Hadoop生態元件Yarn之長期執行服務支援篇!Hadoop元件Yarn
- 詳解展示元件和容器元件的區別和應用元件
- 詳解nginx的請求限制(連線限制和請求限制)Nginx