【無私分享:ASP.NET CORE 項目實戰(第十三章)】Asp.net Core 使用MyCat分佈式數據庫,實現讀寫分離

 

目錄索引 

 

【無私分享:ASP.NET CORE 項目實戰】目錄索引html

 

簡介

 

  

  MyCat2.0版本很快就發佈了,關於MyCat的動態和一些問題,你們能夠加一下MyCat的官方QQ羣:106088787。咱們今天主要介紹一下,在咱們的Asp.net Core中如何使用Mycat,這源於一個大神(Amamiya Yuuko)的分享,可是,這中間仍是有少量的 坑 :前端

  首先,由於大神是比較忙的,並且主要分享關鍵技術,因此有些地方很簡略,而每每這些簡略的地方容易形成新手的困惑。java

 

  其次,在嘗試了N次失敗後,我發現大神的代理程序是有問題的,具體是什麼問題,咱們待會詳細解釋,通過修改以後的代理程序,能夠正常運行。linux

  所以,我以爲頗有必要寫這篇文章,一步一步搭建、測試、運行。git

 

 

什麼是MyCat?

 

   

  

  從定義和分類來看,它是一個開源的分佈式數據庫系統,是一個實現了MySQL協議的服務器,前端用戶能夠把它看做是一個數據庫代理,用MySQL客戶端工具和命令行訪問,而其後端能夠用MySQL原生協議與多個MySQL服務器通訊,也能夠用JDBC協議與大多數主流數據庫服務器通訊,其核心功能是分表分庫,即將一個大表水平分割爲N個小表,存儲在後端MySQL服務器裏或者其餘數據庫裏。github

 

  MyCat發展到目前的版本,已經不是一個單純的MySQL代理了,它的後端能夠支持MySQL、SQL Server、Oracle、DB二、PostgreSQL等主流數據庫,也支持MongoDB這種新型NoSQL方式的存儲,將來還會支持更多類型的存儲。而在最終用戶看來,不管是那種存儲方式,在MyCat裏,都是一個傳統的數據庫表,支持標準的SQL語句進行數據的操做,這樣一來,對前端業務系統來講,能夠大幅下降開發難度,提高開發速度。sql

 

  此外,開發者能夠根據不一樣的需求將表分配不一樣的數據節點,好比Table A存放在關係型數據庫中(如MySQL),而Table B可能更適合NoSQL(如MongoDB),在MyCAT中開發者只須要簡單配置,便可讓MyCAT完成這一系列操做的路由。數據庫

 

   關於更多MyCat,你們能夠參照官網:http://www.mycat.org.cn/json

 

 

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 -Verbosedotnet 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.xmltableRule 標籤的 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

相關文章
相關標籤/搜索