在ASP.NET Core微服务架构下使用数据库切分和扩展

原文链接:https://itnext.io/how-to-use-database-sharding-and-scale-an-asp-net-core-microservice-architecture-22c24916590f

微服务的一大优点是,它们可以独立扩展。本文展示了扩展一个微服务及其数据库的好处和挑战

您将创建一个示例应用程序并手动实现应用程序层分片。它展示了如何根据用例和数据模型选择分片Key。这有助于将相同的原理应用到具有集成扩展(如MongoDB等)的DBMS上。

1.用例和数据模型

示例应用程序由一个User和Post微服务组成。它们通过消息交流: 

User微服务处理添加和修改用户。Post微服务处理查看和添加帖子。因为与Post微服务的交互要多得多,所以,当应用程序的负载增加时,Post微服务将成为第一个需要扩展的微服务。

作者的名字是PostService绑定上下文的一部分,因此也是Post微服务的一部分。在User微服务中添加和修改作者。User微服务在添加新用户或更改用户名时发送事件。

PostService的逻辑数据模型

用户可以分类写文章。他们还可以按类别阅读帖子,包括作者姓名。最新的帖子在上面。分类是固定的,很少改变。

基于这些用例,我决定按类别划分数据库分片:

2.实现微服务

创建解决方案并添加名为“PostService”的ASP.NET Core 5 Web API项目。禁用HTTPS并激活OpenAPI支持。

安装以下NuGet软件包:

  • Microsoft.EntityFrameworkCore.Tools

  • MySql.EntityFrameworkCore

  • Newtonsoft.Json

创建实体

Post实体的索引可以加快检索某个类别中最新的帖子:

using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;namespace PostService.Entities
{[Index(nameof(PostId), nameof(CategoryId))]public class Post{public int PostId { get; set; }public string Title { get; set; }public string Content { get; set; }public int UserId { get; set; }public User User { get; set; }[Required]public string CategoryId { get; set; }public Category Category { get; set; }}
}

User实体中的版本稍后将帮助处理无序消息:

namespace PostService.Entities
{public class User{public int ID { get; set; }public string Name { get; set; }public int Version { get; set; }}
}namespace PostService.Entities
{public class Category{public string CategoryId { get; set; }}
}

创建PostServiceContext

using Microsoft.EntityFrameworkCore;namespace PostService.Data
{public class PostServiceContext : DbContext{private readonly string _connectionString;public PostServiceContext(string connectionString){_connectionString = connectionString;}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseMySQL(_connectionString);}public DbSet<PostService.Entities.Post> Post { get; set; }public DbSet<PostService.Entities.User> User { get; set; }public DbSet<PostService.Entities.Category> Category { get; set; }}
}

在appsettings.Development.json中添加连接字符串(在调试期间将使用两个分片)

{"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"PostDbConnectionStrings": {"Shard0": "server=localhost; port=3310; database=post; user=root; password=pw; Persist Security Info=False; Connect Timeout=300","Shard1": "server=localhost; port=3311; database=post; user=root; password=pw; Persist Security Info=False; Connect Timeout=300"    }
}

添加DataAccess代码

GetConnectionString(string category)计算CategoryId的哈希值。哈希的第一部分将配置的分片数(连接字符串)取模,从而确定给定类别的分片。

InitDatabase删除并重新创建所有分片中的所有表,并插入虚拟用户和类别。

其他方法用于创建和加载帖子。

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using PostService.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;namespace PostService.Data
{public class DataAccess{private readonly List<string> _connectionStrings = new List<string>();public DataAccess(IConfiguration configuration){var connectionStrings = configuration.GetSection("PostDbConnectionStrings");foreach(var connectionString in connectionStrings.GetChildren()){Console.WriteLine("ConnectionString: " + connectionString.Value);_connectionStrings.Add(connectionString.Value);}}public async Task<ActionResult<IEnumerable<Post>>> ReadLatestPosts(string category, int count){using var dbContext = new PostServiceContext(GetConnectionString(category));return await dbContext.Post.OrderByDescending(p => p.PostId).Take(count).Include(x => x.User).Where(p => p.CategoryId == category).ToListAsync();}public async Task<int> CreatePost(Post post){using var dbContext = new PostServiceContext(GetConnectionString(post.CategoryId));dbContext.Post.Add(post);return await dbContext.SaveChangesAsync();}public void InitDatabase(int countUsers, int countCategories){foreach (var connectionString in _connectionStrings){using var dbContext = new PostServiceContext(connectionString);dbContext.Database.EnsureDeleted();dbContext.Database.EnsureCreated();for (int i = 1; i <= countUsers; i++){dbContext.User.Add(new User { Name = "User" + i, Version = 1 });dbContext.SaveChanges();}for (int i = 1; i <= countCategories; i++){dbContext.Category.Add(new Category { CategoryId = "Category" + i });dbContext.SaveChanges();}}}private string GetConnectionString(string category){using var md5 = MD5.Create();var hash = md5.ComputeHash(Encoding.ASCII.GetBytes(category));var x = BitConverter.ToUInt16(hash, 0) % _connectionStrings.Count;return  _connectionStrings[x];}}
}

在Startup.cs中将DataAccess注册为单例

public class Startup
{...public void ConfigureServices(IServiceCollection services){services.AddControllers();services.AddSwaggerGen(c =>{c.SwaggerDoc("v1", new OpenApiInfo { Title = "PostService", Version = "v1" });});services.AddSingleton<DataAccess>();}---

创建PostController

它使用DataAccess类

using Microsoft.AspNetCore.Mvc;
using PostService.Data;
using PostService.Entities;
using System.Collections.Generic;
using System.Threading.Tasks;namespace PostService.Controllers
{[Route("api/[controller]")][ApiController]public class PostsController : ControllerBase{private readonly DataAccess _dataAccess;public PostsController(DataAccess dataAccess){_dataAccess = dataAccess;}[HttpGet]public async Task<ActionResult<IEnumerable<Post>>> GetLatestPosts(string category, int count){return await _dataAccess.ReadLatestPosts(category, count);}[HttpPost]public async Task<ActionResult<Post>> PostPost(Post post){await _dataAccess.CreatePost(post);return NoContent();}[HttpGet("InitDatabase")]public void InitDatabase([FromQuery] int countUsers, [FromQuery] int countCategories){_dataAccess.InitDatabase(countUsers, countCategories);}}
}

3. 用PostService访问数据库

安装Docker Desktop。

创建两个MySql容器

C:\dev>docker run -p 3310:3306 --name=mysql1 -e MYSQL_ROOT_PASSWORD=pw -d mysql:5.6
C:\dev>docker run -p 3311:3306 --name=mysql2 -e MYSQL_ROOT_PASSWORD=pw -d mysql:5.6

在Visual Studio中启动Post服务。浏览器在打开http://localhost:5001/swagger/index.html

使用swagger UI与服务交互:

初始化包含100个用户和10个类别的数据库: 

在“Category1”下增加一个帖子:

{"title": "MyTitle","content": "MyContent","userId": 1,"categoryId": "Category1"
}

阅读“Category1”中排名前10位的帖子:

连接到数据库容器并验证哪个数据库包含新的帖子

C:\dev>docker container exec -it mysql1 /bin/sh

使用密码“pw”登录MySql并读取帖子: 

第二个实例不包含任何帖子:

C:\dev>docker container exec -it mysql2 /bin/sh

4.最后的想法和展望

您创建了一个可工作的应用程序,实现了应用程序层分片,并使用了分片Key的概念。

这只是一个示例应用程序。您必须调整代码才能在生产环境中使用它。

在第二部分中,您将缩放并运行微服务和数据库的多个容器实例。您将使用docker compose和负载平衡器。然后,您将运行JMeter负载测试,以查看应用程序在使用不同数量的实例时是如何伸缩的。最后,您将通过RabbitMQ模拟来自用户微服务的用户事件。

欢迎关注我的个人公众号”My IO“

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/301293.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GridView实现数据编辑和删除(一)

2019独角兽企业重金招聘Python工程师标准>>> 前台的html代码&#xff1a; <asp:GridView ID"gv_Emplogin" runat"server" AutoGenerateColumns"False" onrowdeleting"gv_Emplogin_RowDeleting" onrowupdating"gv_…

8张图告诉你,在朋友圈发什么不会被嫌弃

爱发圈的你是否发现&#xff0c;打开朋友圈总有一些内容让你嫌弃&#xff1a;和本人真假难辨的美图自拍&#xff0c;每天十条以上的发帖&#xff0c;伪科普的转发…还有一些人你直接想删除&#xff1a;炫耀自己家的奢侈品&#xff0c;从不交摊位费的代购和微商和一日三餐都发圈…

iNeuOS工业互联网平台,在高校教学实训领域的应用

目 录1. 概述... 22. 实训柜... 23. 培训内容... 44. 二次开发培训... 51. 概述中国工业互联网从 0 向 1 演进从缺政策、缺技术、缺市场&#xff0c;逐渐转移到了缺人才&#xff0c;跨行业、跨领域的复合型人才&#xff1b;IT与OT融合型人才&#…

keepalived 原理,安装,配置

什么是Keepalived呢&#xff0c;keepalived观其名可知&#xff0c;保持存活&#xff0c;在网络里面就是保持在线了&#xff0c;也就是所谓的高可用或热备&#xff0c;用来防止单点故障(单点故障是指一旦某一点出现故障就会导致整个系统架构的不可用)的发生&#xff0c;那说到ke…

28合1智能积木,56种玩法,让孩子循序渐进“玩”出新知识

▲数据汪特别推荐点击上图进入玩酷屋小木作为一名资深积木达人&#xff0c;我可是大大小小的积木阅览无数&#xff0c;最近小木又发现一个超好玩的----28合1小卡百变积木&#xff01;小卡百变积木是小卡团队研发的一款全新概念的智能积木&#xff0c;由276颗高精度积木&#xf…

表3.5 文章管理测试用例表_本地管理表空间管理机制

表空间是一种为段&#xff08;表&#xff0c;索引等&#xff09;提供空间的逻辑结构&#xff0c;所以&#xff0c;当在表空间中增加&#xff0c;删除段的时候&#xff0c;数据库就必须跟踪这些空间的使用。如下例所示&#xff0c;假定一个新创建的表空间包含了五个表表一……表…

.NET | 多线程下的调用上下文 : CallContext

【.NET】| 总结/Edison Zhou最近在分析现在团队的项目代码&#xff08;基于.NET Framework 4.5&#xff09;&#xff0c;经常发现一个CallContext的调用&#xff0c;记得多年前的时候用到了它&#xff0c;但是印象已经不深刻了&#xff0c;于是现在来复习一下。1CallContext是个…

每日一笑 | 哪个男人到底是谁?!

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图源网络&#xff0c;侵权删&#xff09;

min里所有的参数都不存在_高中生物所有的考点难点,其实都在你不仔细看的课本里,必修1-3超强记忆手册!...

对很多理科生来说&#xff0c;高中生物就是一门不是文科胜似文科的学科。很多数学、物理成绩非常突出的学生却不能在这样一门“理科”课程当中取得优势。生物老师在这门学科的提高上反复强调“回归课本”却又让很多习惯刷题的理科生不知无从下手。进入高三后&#xff0c;生物、…

我看电商(作者近三十年从事零售及电子商务管理的总结和分享)

我看电商&#xff08;作者近三十年从事零售及电子商务管理的总结和分享&#xff09; 黄若 著 ISBN 978-7-121-20268-1 2013年6月出版 定价&#xff1a;39.00元 284页 16开 编辑推荐 近年来电商行业在中国迅猛发展&#xff0c;电子商务正在日益深入的影响着越来越多人的生活。…

每日一笑 | 坐牢吗?学编程那种~

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图源网络&#xff0c;侵权删&#xff09;

VMware vSphere 5.1 群集深入解析(二十六)- 数据存储维护模式汇总

VMware vSphere5.1Clustering DeepdiveHA.DRS.Storage DRS.Stretched ClustersDuncan Epping &Frank DennemanTranslate By Tim2009 / 翻译&#xff1a;Tim2009目录版权关于作者知识点前言第一部分 vSphere高可用性第一章 介绍vSphere高可用性第二章 高可用组件第三章 基本…

硕士论文研究「AI预测性取向」:化妆等因素并不影响判断

全世界只有3.14 % 的人关注了数据与算法之美2017 年&#xff0c;斯坦福大学的一篇《深度学习通过面部识别判断性取向超越人类》曾引发了极大争议&#xff0c;其通过 AI 算法仅需「看面相」即可判断一个人是不是同性恋的方法让众人感到一丝恐慌&#xff0c;也让技术研究者们对于…

[翻译]Go与C#对比 第三篇:编译、运行时、类型系统、模块和其它的一切

Go vs C#, Part 3: Compiler, Runtime, Type System, Modules, and Everything Else | by Alex Yakunin | ServiceTitan — Titan Tech | Medium目录译者注相似性编译垃圾回收模块类、结构、接口错误处理相等性&#xff08;, !&#xff09;基础类库两种语言中存在的其他类似特…

指针易出错点一

2019独角兽企业重金招聘Python工程师标准>>> 声明指针中会遇到的问题 int* p1,p2; 上面这条语句的本意应该是声明两个指向int的指针&#xff0c;而实际的效果是p1是指针类型&#xff0c;p2却是int类型&#xff0c;这是因为在C语言中&#xff0c;声明和解释的语法并…

206块积木,72套进阶玩法!玩转STEAM教育,帮你省掉上万块的乐高课

▲数据汪特别推荐点击上图进入玩酷屋作为一名资深积木达人&#xff0c;小木我可是大大小小的积木阅览无数&#xff0c;当然乐高也不会放过&#xff0c;虽然“钱包君”已经是路人了。&#xff08;每月的工资用来买乐高~&#xff09;之前给大家推荐了一款STEM积木&#xff0c;小小…

python如何正则匹配浮点值_python使用正则搜索字符串或文件中的浮点数代码实例...

# -*- coding: utf-8 -*-#----------------------------------------------------------------------# FileName:gettxtdata.py#功能:读取字符串和文件中的数值数据(浮点数)#主要提供类似matlab中的dlmread和dlmwrite函数#同时提供loadtxtdata和savetxtdata函数#Data: 2013-1-1…

用了VS2022,你可能再也回不去旧版!

VS2022发布第11天&#xff0c;最直接的使用感受就是智能提示太哇塞了&#xff0c;之前是提示一个单词&#xff0c;现在直接提示一行&#xff0c;撸码速度直接起飞&#xff01;再就是打开ASP.NET Core的源码&#xff0c;500多个项目3G的体积&#xff0c;过程比VS2019要顺滑多了&…

poj2578

简单题 #include <cstdio>int main() {int f[5];for (int i 0; i < 3; i){scanf("%d", &f[i]);if (f[i] < 168){printf("CRASH %d\n", f[i]);return 0;}}printf("NO CRASH\n");return 0; } View Code 转载于:https://www.cnblo…

意大利归还中国文物;翟天临咪蒙成考公务员题目;携程回应五一机票涨价;腾讯未成年人网络保护体系上线;这就是今天的大新闻...

今天是3月25日农历二月十九今天星期一整个周末都贡献给都挺好了下面是今天的大新闻意大利归还796件中国文物&#xff08;新京报&#xff09;3月23日&#xff0c;在中国主席和意大利总理孔特共同见证下&#xff0c;中意双方代表交换关于796件套中国流失文物艺术品返还的证书。这…