目录索引 

【无私分享:ASP.NET CORE 项目实战】目录索引

简介

  

  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

【无私分享:ASP.NET CORE 项目实战(第十三章)】Asp.net Core 使用MyCat分布式数据库,实现读写分离的更多相关文章

  1. 【无私分享:ASP.NET CORE 项目实战(第九章)】创建区域Areas,添加TagHelper

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在Asp.net Core VS2015中,我们发现还有很多不太简便的地方,比如右击添加视图,转到试图页等功能图不见了,虽然我 ...

  2. 【无私分享:ASP.NET CORE 项目实战(第二章)】添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 上一章,我们介绍了安装和新建控制器.视图,这一章我们来创建个数据模型,并且添加接口和实现类. 添加EF上下文对象 按照我们以前 ...

  3. [转]【无私分享:ASP.NET CORE 项目实战(第九章)】创建区域Areas,添加TagHelper

    本文转自:http://www.cnblogs.com/zhangxiaolei521/p/5808417.html 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 在Asp ...

  4. .NET Core IdentityServer4实战 第三章-使用EntityFramework Core进行持久化配置

    内容:本文带大家使用IdentityServer4进行使用使用EntityFramework Core进行配置和操作数据 作者:zara(张子浩) 欢迎分享,但需在文章鲜明处留下原文地址. 前两章内容 ...

  5. 【无私分享:ASP.NET CORE 项目实战】目录索引

    简介 首先,我们的  [无私分享:从入门到精通ASP.NET MVC]   系列已经接近尾声,希望大家在这个过程中学到了一些思路和方法,而不仅仅是源码. 因为是第一次写博客,我感觉还是比较混乱的,其中 ...

  6. 【无私分享:ASP.NET CORE 项目实战(第十四章)】图形验证码的实现

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 很长时间没有来更新博客了,一是,最近有些忙,二是,Core也是一直在摸索中,其实已经完成了一个框架了,并且正在准备在生产环境中 ...

  7. 【无私分享:ASP.NET CORE 项目实战(第十二章)】添加对SqlServer、MySql、Oracle的支持

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 增加对多数据库的支持,并不是意味着同时对多种数据库操作,当然,后面,我们会尝试同时对多种数据库操作,这可能需要多个上下文,暂且 ...

  8. 【无私分享:ASP.NET CORE 项目实战(第十一章)】Asp.net Core 缓存 MemoryCache 和 Redis

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitHub上下载了十几个源码参考, Memory 和 Redis 终于写出一个 ...

  9. 【无私分享:ASP.NET CORE 项目实战(第十章)】发布项目到 Linux 上运行 Core 项目

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 ASP.Net Core 给我们带来的最大的亮点就是跨平台,我在我电脑(win7)上用虚拟机建了个 CentOS7 ,来演示下 ...

随机推荐

  1. 在你的ASP.NET MVC中使用查找功能

    在程序中,使用查找功能是少之不了.今天在ASP.NET环境下演示一回. 在cshtml视图中,有三个文本框,让用户输入关键词,然后点击最右连的“搜索”铵钮,如果有结果将显示于下面. Html: 表格放 ...

  2. WinForm设置控件焦点focus

    winform窗口打开后文本框的默认焦点设置,进入窗口后默认聚焦到某个文本框,两种方法: ①设置tabindex 把该文本框属性里的tabIndex设为0,焦点就默认在这个文本框里了. ②Winfor ...

  3. 深入学习HBase架构原理

    HBase定义 HBase 是一个高可靠.高性能.面向列.可伸缩的分布式存储系统,利用Hbase技术可在廉价PC Server上搭建 大规模结构化存储集群. HBase 是Google Bigtabl ...

  4. crontab介绍

    1.Cron的启动与关闭 由于Cron是Linux的内置服务,可以用以下的方法启动.关闭这个服务: /sbin/service crond start           //启动服务/sbin/se ...

  5. 免费SSL证书 之Let’s Encrypt申请与部署(Windows Nginx)

    我着着皇帝的新衣,但是你看不见    有一颗愿意等待的心,说明你对未来充满希望.有一颗充满希望的心,那么等待又算什么.人就是在等待与希望中度过,我们永远要对未来充满信心! 读在最前面: 1.本文案例为 ...

  6. 微软发布 Windows Server 2016 预览版第三版,开发者要重点关注Nano Server

    微软已经发布 Windows Server 2016 和 System Center 2016 第三个技术预览版,已经提供下载.Windows Server 2016 技术预览版第三版也是首个包括了容 ...

  7. 整理Ajax的点点滴滴

    最近看了下<Javascript高级程序设计>(第三版)关于Ajax部分,做了这篇笔记. 一.常规用法 第一步,创建XHR对象var xhr = new XMLHttpRequest(); ...

  8. 一种简单的CQRS架构设计及其实现

    一.为什么要实践领域驱动? 近一年时间我一直在思考一个问题:"如何设计一个松耦合.高伸缩性.易于维护的架构?".之所以有这样的想法是因为我接触的不少项目都是以数据库脚本来实现业务逻 ...

  9. 模仿EF,我们用JS开发的HTML5 SQLite 访问库

    今天终于有空把demo放到了RunJS上面去.请使用google chrome观看在线演示: http://sandbox.runjs.cn/show/pekbd9zb 这个库本来是我们开发的phon ...

  10. 程序猿是如何解决SQLServer占CPU100%的

    文章目录 遇到的问题 使用SQLServer Profiler监控数据库 SQL1:查找最新的30条告警事件 SQL2:获取当前的总报警记录数 有哪些SQL语句会导致CPU过高? 查看SQL的查询计划 ...