目錄索引 【無私分享:ASP.NET CORE 項目實戰】目錄索引 簡介 MyCat2.0版本很快就發佈了,關於MyCat的動態和一些問題,大家可以加一下MyCat的官方QQ群:106088787。我們今天主要介紹一下,在我們的Asp.net Core中如何使用Mycat,這源於一個大神(Amami ...
目錄索引
簡介
MyCat2.0版本很快就發佈了,關於MyCat的動態和一些問題,大家可以加一下MyCat的官方QQ群:106088787。我們今天主要介紹一下,在我們的Asp.net Core中如何使用Mycat,這源於一個大神(Amamiya Yuuko)的分享,但是,這中間還是有少許的 坑 :
首先,因為大神是比較忙的,而且主要分享關鍵技術,所以有些地方很簡略,而往往這些簡略的地方容易造成新手的困惑。
其次,在嘗試了N次失敗後,我發現大神的代理程式是有問題的,具體是什麼問題,我們待會詳細解釋,經過修改之後的代理程式,可以正常運行。
因此,我覺得很有必要寫這篇文章,一步一步搭建、測試、運行。
什麼是MyCat?
從定義和分類來看,它是一個開源的分散式資料庫系統,是一個實現了MySQL協議的伺服器,前端用戶可以把它看作是一個資料庫代理,用MySQL客戶端工具和命令行訪問,而其後端可以用MySQL原生協議與多個MySQL伺服器通信,也可以用JDBC協議與大多數主流資料庫伺服器通信,其核心功能是分表分庫,即將一個大表水平分割為N個小表,存儲在後端MySQL伺服器里或者其他資料庫里。
MyCat發展到目前的版本,已經不是一個單純的MySQL代理了,它的後端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流資料庫,也支持MongoDB這種新型NoSQL方式的存儲,未來還會支持更多類型的存儲。而在最終用戶看來,無論是那種存儲方式,在MyCat里,都是一個傳統的資料庫表,支持標準的SQL語句進行數據的操作,這樣一來,對前端業務系統來說,可以大幅降低開發難度,提升開發速度。
此外,開發者可以根據不同的需求將表分配不同的數據節點,比如Table A存放在關係型資料庫中(如MySQL),而Table B可能更適合NoSQL(如MongoDB),在MyCAT中開發者只需要簡單配置,即可讓MyCAT完成這一系列操作的路由。
關於更多MyCat,大家可以參照官網:http://www.mycat.org.cn/
MyCat的優勢
- 基於阿裡巴巴的開源項目Cobar,具備良好的穩定性、可靠性、優良的結構和優良的性能,擁有許多的項目案例。站在巨人的肩膀上,MyCAT將走的更遠。
- 廣泛借鑒最好的開源項目和創新的理念,讓這些融入MyCAT的基因,使MyCAT成為領先其他電商等類似的開源項目,甚至超過了一些企業級應用。
- MyCAT技術團隊的參與者都經歷過至少五多年的項目經驗,團隊中包括一些高級軟體工程師、架構師、DBA。由精英們組成的MyCAT技術團隊將確保產品質量。
- MyCAT是完全獨立的社區,不依附於任何企業,遵循著完全開放、免費、開源的原則。它不像一些開源項目,重要的功能封閉在其商業產品,並使開源項目像一個裝飾。
- 支持超過60種的資料庫作為數據節點,如MySQL、SQL Server、Oracle、MongoDB、DB2等
MyCat與ADO.NET
由於MyCAT與MySQL協議有些許差異,開發者可能不能夠直接使用Oracle官方提供的Mysql.Data(ADO層)來與MyCAT直接連接,因此有大神專門為.NET開發者設計了針對MyCAT優化過的ADO層驅動,即 Pomelo.Data.MyCat,開發者通過使用MyCatConnection、MyCatCommand類可以實現對MyCAT的連接與查詢。
MyCat 與 Entity Framework Core
由於MyCAT的協議與MySQL有所差異,導致了無論是Java平臺下的Hibernate還是.NET下的Entity Framework都無法使用MySQL的provider直接來操作MyCAT。這點在EF中的Migrations以及Code First上表現的尤為明顯,此外開發者不僅需要手動建庫,還需要配置分片規則等,操作繁瑣。
因此我們使用第三方專門為MyCAT量身打造的Entity Framework Core Provider,即 Pomelo.EntityFrameworkCore.MyCat。
安裝Java8
MyCat 需要 java cdk的支持,安裝方法網上很多很詳細,這裡我們就不羅列了。
下載MyCat Server
廢話不多說,我們來開始我們的MyCat之旅:
我們演示使用的伺服器是:CentOS7 當然,Windows 也是支持的,我們以 CentOS為例。
首先,我們在伺服器安裝 MySQL ,這裡我安裝的是 MySQL 5.7,關於 MySQL的安裝,我們這裡就不演示了,沒有裝過的朋友,網上有大片的詳細安裝步驟。值得註意的是,安裝完MySQL之後,我們需要編輯 my.cnf 文件,將MySQL的預設編碼設置為 UTF8 。
我們下載 MyCat Server :我是通過 wget XXXXXXXX;大家也可以直接下載下來,然後通過 FTP 傳到伺服器上。
因為我們是Linux,所以我選擇 linux.tar.gz,使用 Windows的朋友可以選擇 win.tar.gz
[root@bogon ~]# wget https://github.com/MyCATApache/Mycat-download/blob/master/1.5-RELEASE/Mycat-server-1.5.1-RELEASE-20160816173057-linux.tar.gz
解壓 MyCat Server 壓縮包:[root@bogon ~]# tar -xzvf Mycat-server-1.5.1-RELEASE-20160816173057-linux.tar.gz
將文件移動至 /usr/local/mycat 目錄下:[root@bogon ~]# mv mycat /usr/local/mycat
這樣,我們的 MyCat Server,就完成了,我們來運行一下:
打開mycat/bin目錄,運行 ./mycat start ,通過 ./mycat status 查看 mycat的運行情況
啟動:./mycat start 重新啟動:./mycat restart 停止:./mycat stop 狀態:./mycat status
下載 運行代理程式
我們使用的代理程式是由 Amamiya Yuuko 寫的 Pomelo.EntityFrameworkCore.MyCat.Proxy
這個代理程式是由問題的,我們前面說過了,我們先來嘗試一下,對於出現的問題和解決方式,我們再講解。
我們先下載這個代理程式,下在方法跟上面 MyCat Server 一樣,可以使用多種方式,大家可以直接下載到本地,解壓完成後,把解壓的文件通過FTP上傳至proxy目錄,我這裡還是使用 wget
[root@bogon ~]# wget https://github.com/PomeloFoundation/Entity-Framework-Core-MyCat-Proxy/releases/download/1.0.0-alpha2/MyCat-Entity-Framework-Core-Proxy.1.0.0-alpha2-netcore100.zip
創建一個目錄 proxy ,將壓縮包移動到此目錄下:
[root@bogon ~]# mkdir proxy
[root@bogon ~]# mv MyCat-Entity-Framework-Core-Proxy.1.0.0-alpha2-netcore100.zip proxy/MyCat-Entity-Framework-Core-Proxy.1.0.0-alpha2-netcore100.zip
進入 proxy ,並解壓 MyCat-Entity-Framework-Core-Proxy.1.0.0-alpha2-netcore100.zip 壓縮包:
[root@bogon ~]# cd proxy
[root@bogon proxy]# unzip MyCat-Entity-Framework-Core-Proxy.1.0.0-alpha2-netcore100.zip
編輯 config.json 文件,修改 MyCatRoot為"/usr/local/mycat":
安裝.NET Core SDK for CentOS
詳見:【(第十章)】發佈項目到 Linux 上運行 Core 項目
運行代理程式
我們來運行一下代理程式:[root@bogon proxy]# dotnet Pomelo.EntityFrameworkCore.MyCat.Proxy.dll
我們先不管在程式中是怎麼實現MyCat的,這個後面我們再講,我們先來測試一下這個代理程式,不先解決這個代理的問題,到後面都很難知道到底是程式出錯還是伺服器的問題還是代理的問題:
我在VS2015的控制台里執行:Add-Migration MySQL_Init(也可以使用命令:dotnet ef Migrations add MySQL_Init)
出錯了。。。這個錯誤是操作超時了,這極有可能是連接不上MyCat伺服器,這個問題曾困擾了我一段時間,後來突然發現忽略了一個重要的東西,防火牆。。。
我們的代理使用的是7066埠,我們來開啟一下防火牆埠,並重啟防火牆:
[root@bogon ~]# firewall-cmd --zone=public --add-port=7066/tcp --permanent
[root@bogon ~]# systemctl restart firewalld
我們再來執行 Add-Migration MySQL_Init :
創建資料庫: Update-Database -Verbose (dotnet ef database update)
創建成功,看似沒有什麼問題。
我們來插入幾條數據看下:出錯了 Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
超時,伺服器沒有響應。這是怎麼回事呢,我們通過 Navicat 來連接一下 MyCat(同樣伺服器防火牆要開啟 8066 埠,預設MyCat 是8066 埠,方法同上):
首先,我們來檢查一下我們的MyCat狀態:
MyCat Server 關閉了。。。我們重啟:
重啟之後,總是自動關閉。這是什麼原因?我們看下日誌(/usr/local/mycat/logs/wrapper.log):
這下看清楚了,是因為rule columns 有多個 values值,這個是什麼東西呢,這是就是配置MyCat 規則的拆分的列的名稱。
我們來看下代理生成的rule(/usr/local/mycat/conf/rule.xml):
也就是說:MyCat 這個拆分規則 只支持單個,但是我們的代理生成了多個,導致 MyCat Server 錯誤。
我這裡修改一下,改成<columns>ID</columins>,MyCat 啟動就沒有問題了,但是問題來了,我這裡有四個實體類,其中有三個的主鍵都是ID,但是有一個的主鍵是UserID,那麼只根據ID拆分顯然是不合理的。
我們來看下 schema (/usr/local/mycat/conf/schema.xml):
大家註意 table 標簽的 rule 屬性,都是 db_wkmvc_rule 跟 rule.xml 的 tableRule 標簽的 name 屬性是對應的。也就是說,這個表,按照 rule=""的規則,根據columns的值(列名,這裡是主鍵也就是ID或UserID)拆分數據。
如何解決?
我想到的方案就是,每個表一個單獨的規則,每個規則的columns值就是當前這個表的主鍵。
我們來看下代理程式的源碼:
根據方法名稱,我們可以看出這兩個方法應該就是修改 rule.xml 和 schema.xml
我們來看下GenerateRuleXml() :
這一段就是生成xml內容的,為什麼我們的 rule.xml 中的 columns 會生成 諸如:ID,ID,ID,UserID 呢?我們可以很清楚的看出 <columns>{ string.Join(",", s.Keys.First()) }</columns>
在 foreach 迴圈 schema.xml 中 table 標簽的時候,把他們的 Key (primaryKey) 通過 string.join 組合起來了,並且只生成了一個 tableRule
那麼,按照我們的方案,應該是每個表(在 schema.xml 中體現就是 一個 table 標簽),單獨生成一個 規則。
修改起來也很簡單:
我們把迴圈中的 ruleXml="" 改為 rulexml+="",然後把 <columns>{ string.Join(",", s.Keys.First()) }</columns> 改為當前表的 primaryKey :<columns>{ s.Keys.First() }</columns>
這是修改後的完整的 public void GenerateRuleXml(List<MyCatTable> Schema, List<MyCatDataNode> DataNodes, string database, bool IsUnder16)
public void GenerateRuleXml(List<MyCatTable> Schema, List<MyCatDataNode> DataNodes, string database, bool IsUnder16)
{
foreach(var s in Schema)
{
if (s.Keys.Count() != 1)
continue;
string ruleXml = "";
string funcXml = "";
if (IsUnder16)
{
ruleXml += $@"
<tableRule name=""{ database }_{ s.TableName }_rule"">
<rule>
<columns>{ s.Keys.First() }</columns>
<algorithm>{ database }_{ s.TableName }_func</algorithm>
</rule>
</tableRule>
";
funcXml += $@"
<function name=""{ database }_{ s.TableName }_func"" class=""org.opencloudb.route.function.PartitionByMod"">
<property name=""count"">{ s.DataNodes.Count() }</property>
</function>
";
}
else // 1.6+
{
ruleXml += $@"
<tableRule name=""{ database }_{ s.TableName }_rule"">
<rule>
<columns>{ s.Keys.First() }</columns>
<algorithm>{ database }_{ s.TableName }_func</algorithm>
</rule>
</tableRule>
";
funcXml += $@"
<function name=""{ database }_{ s.TableName }_func"" class=""io.mycat.route.function.PartitionByMod"">
<property name=""count"">{ s.DataNodes.Count() }</property>
</function>
";
}
using (var reader = XmlReader.Create(Path.Combine(MyCatRoot, "conf", "rule.xml"), new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }))
{
var xml = new XmlDocument();
xml.Load(reader);
var mycatRule = xml.ChildNodes.Cast<XmlNode>().Single(x => x.Name == "mycat:rule");
foreach (var x in mycatRule.ChildNodes.Cast<XmlNode>().Where(x => (x.Name == "tableRule" && x.Attributes["name"].Value == $"{ database }_{ s.TableName }_rule") || (x.Name == "function" && x.Attributes["name"].Value == $"{ database }_{ s.TableName }_func")).ToList())
mycatRule.RemoveChild(x);
mycatRule.InnerXml = ruleXml + mycatRule.InnerXml;
mycatRule.InnerXml += funcXml;
reader.Dispose();
File.WriteAllText(Path.Combine(MyCatRoot, "conf", "rule.xml"), PatchXml("rule", xml.OuterXml));
}
}
}
我們重新編譯生成,發佈出來上傳至伺服器,替換掉我們之前的代理程式。然後重新運行一下,我們再來看下 rule.xml 和 schema.xml:
是不是按照我們的預期,我們看下MyCat Server的狀態:
MyCat 連接也沒問題了
(後記:關於這個代理的問題,已經提交給作者了,這個代理程式我測試有一段時間了,當時還是alpha1版本,寫文章的時候,我看到 alpha2版本貌似改進了,但是源碼沒有修改。)
如何在Asp.net Core中使用 Mycat
分兩部分,第一部分就是最簡潔的應用,第二部分是我在項目中的應用,大家自行參考。
第一部分,最簡潔的應用(作者 Demo):
首先,我們新建一個控制台程式
並將 Pomelo.EntityFrameworkCore.MyCat
添加至 project.json 中(Nuget:Install-Package Pomelo.EntityFrameworkCore.MyCat -Pre)
創建一個Blog模型:
public class Blog
{
public long Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Time { get; set; }
}
創建DbContext類,並重寫DbContext中的OnConfiguring方法,配置數據節點以及MyCAT伺服器信息
public class SampleContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseMyCat("server=IP;port=8066;uid=test;pwd=test;database=blogs")
.UseDataNode("IP", "blogs_1", "用戶名", "密碼")
.UseDataNode("IP", "blogs_2", "用戶名", "密碼")
.UseDataNode("IP", "blogs_3", "用戶名", "密碼");
}
}
註意:
.UseMyCat()中的 Server 是 MyCat 伺服器的地址 Uid 和 Pwd 是 MyCat 的 用戶名和密碼,不要和數據的混了。
.UseDataNode()中的 Server 是節點資料庫的地址 Uid 和 Pwd 是節點資料庫的 用戶名和密碼。
如何查看 MyCat 的用戶名和密碼:
打開mycat目錄下的 conf 目錄(我們這裡是:/usr/local/mycat/conf)
查看 server.xml 文件:
上面插入一段,一般使用mycat的應該都知道這些文件分別是乾什麼的,我們這裡啰嗦一下。
我把整個的 Program.cs 內容給大家展示一下:
然後,就不多說了,你可以使用控制台命令 Add-Migration 和 Update-database 也可以使用命令 dotnet ef migrations add 和 dotnet ef database update 執行遷移和其它操作了。
第二部分,我在項目中的應用:
首先,在配置文件(siteconfig.json)中添加一個是否使用 MyCat 的配置:
然後,同樣在配置文件(siteconfig.json)中添加資料庫節點配置:
在 【(第十二章)】添加對SqlServer、MySql、Oracle的支持 中,我們有個資料庫選擇類 DataBaseProvider.cs
這裡面已經寫了一個 _isUseMyCat 和 GetMyCatConnect(),是否使用 MyCat 這個 跟 資料庫選擇一樣,我們從配置文件中讀取這個配置返回即可:
我們來重寫一下 GetMyCatConnect 返回 MyCat 和 節點資料庫連接的 DbContextOptionsBuilder:
public DbContextOptionsBuilder GetMyCatConnect(string connectionStr, DbContextOptionsBuilder _options)
{
_options.UseMyCat(connectionStr);
List<MyCatDatabaseHost> hosts = new Services.ConfigServices.AppConfigurtaionServices().GetListAppSettings<MyCatDatabaseHost>("MyCatDatabaseHost");
foreach(var host in hosts)
{
_options.UseDataNode(host.Host, host.Database, host.Username, host.Password, host.Port);
}
return _options;
}
對於讀取配置的方法,我們在 【(第十二章)】添加對SqlServer、MySql、Oracle的支持 中已經完整的貼出。
修改一下 Startup.cs :
這樣,我們就實現了對 MyCat的支持和切換,當然,在實際項目中,我們可能不需要這些,使用什麼,是否有必要使用 MyCat 這些可能是早就定好的,因為我這個是測試學習的項目,所以羅列了各種東西。
希望跟大家一起學習Asp.net Core
剛開始接觸,水平有限,很多東西都是自己的理解和翻閱網上大神的資料,如果有不對的地方和不理解的地方,希望大家指正!
雖然Asp.net Core 現在很火熱,但是網上的很多資料都是前篇一律的複製,所以有很多問題我也暫時沒有解決,希望大家能共同幫助一下!
原創文章 轉載請尊重勞動成果 http://yuangang.cnblogs.com