在 Docker Swarm 模式下使用 ASP.NET Core 和 RethinkDB 构建可扩展、容错的系统
介绍
本指南向您展示如何将 RethinkDB 与 ASP.NET Core 结合使用,以及如何使用 Docker for Windows 和 Docker Swarm 模式将您的应用程序与 RethinkDB 集群一起部署。我们将使用《使用 Docker Swarm 模式扩展ASP.NET Core 应用程序》指南中的 TokenGen 应用程序,并将生成的令牌与发行者一起存储在 RethinkDB 数据库中。
RethinkDB 是一个开源的分布式文档型数据库。与大多数 NoSQL 数据库一样,它存储 JSON 文档,不需要任何架构或表结构。
RethinkDB 的优点:
- 水平扩展
- 表复制和共享
- 自动故障转移
- 具有连接支持、map-reduce 和地理空间查询的查询语言
- 数据变更的发布/订阅
如果您想要为 ASP.NET Core 应用程序提供可扩展、容错的数据库系统,那么您应该考虑使用 RethinkDB。
使用Docker Swarm模式设置RethinkDB集群
首先,我们需要启用 Swarm 模式并为我们的 RethinkDB 集群创建专用网络:
# initialize swarm
docker swarm init
# create RethinkDB overlay network
docker network create --driver overlay rdb-net
我们通过运行单个 RethinkDB 服务器开始构建我们的 RethinkDB 集群,稍后我们将删除此实例:
# create and start rethinkdb primary
docker service create --name rdb-primary --network rdb-net --replicas 1 rethinkdb:latest rethinkdb --bind all --no-http-admin
现在我们可以创建一个辅助 RethinkDB 节点,该节点将加入rdb-primary节点并形成集群:
# create and start rethinkdb secondary
docker service create --name rdb-secondary --network rdb-net --replicas 1 rethinkdb:latest rethinkdb --bind all --no-http-admin --join rdb-primary
扩展辅助节点,以便我们可以拥有 RethinkDB 自动故障转移机制所需的至少 3 个节点:
# up 3 nodes (primary + two secondary) to enable automatic failover
docker service scale rdb-secondary=2
我们现在有一个可运行的 RethinkDB 集群,但我们还没有完成。由于我们在没有使用 join 命令的情况下启动了主节点,因此我们的集群存在单点故障。如果由于某种原因rdb-primary容器崩溃,Docker Swarm 引擎将重新创建并启动此容器,但它无法加入现有集群。如果我们启动新的rdb-secondary实例,它们将加入新的rdb-primary容器并形成另一个集群。
为了解决这个问题,我们必须删除rdb-primary服务并使用join命令重新创建它,如下所示:
# remove primary
docker service rm rdb-primary
# recreate primary with --join flag
docker service create --name rdb-primary --network rdb-net --replicas 1 rethinkdb:latest rethinkdb --bind all --no-http-admin --join rdb-secondary
现在我们也可以扩展主节点:
# start two rdb-primary instances
docker service scale rdb-primary=2
此时,我们的集群中有 4 个节点,两个rdb-primary和两个rdb-secondary。我们可以进一步扩展这两个服务中的任何一个,它们都将加入我们的集群。如果rdb-primary或rdb-secondary实例崩溃,Docker Swarm 将自动启动另一个容器并加入我们当前的集群。
最后一步是创建一个 RethinkDB 代理节点,我们为 Web 管理员公开端口 8080,并公开端口 28015,以便我们可以从我们的应用程序连接到集群。请注意,如果您的应用程序在 Swarm 中运行,则不必公开端口 28015。我公开此端口是为了在 VS.NET 中调试时连接到集群。
# create and start rethinkdb proxy
docker service create --name rdb-proxy --network rdb-net --publish 8080:8080 --publish 28015:28015 rethinkdb:latest rethinkdb proxy --bind all --join rdb-primary
打开浏览器并导航到https://localhost:8080以检查集群状态。在服务器页面中,您应该看到 4 个服务器连接到集群。
如果我们运行docker service ls我们应该得到:
ID NAME REPLICAS IMAGE COMMAND
157bd7yg7d60 rdb-secondary 2/2 rethinkdb:latest rethinkdb --bind all --no-http-admin --join rdb-primary
41eloiad4jgp rdb-primary 2/2 rethinkdb:latest rethinkdb --bind all --no-http-admin --join rdb-secondary
67oci5m1wksi rdb-proxy 1/1 rethinkdb:latest rethinkdb proxy --bind all --join rdb-primary
从 ASP.NET Core 连接到 RethinkDB
打开上一指南中的 TokenGen 项目并安装 RethinkDB 驱动程序 NuGet 包:
Install-Package RethinkDb.Driver
我们将创建一个保存 RethinkDB 集群地址的对象。在 TokenGen 项目中添加一个名为RethinkDbOptions的类:
public class RethinkDbOptions
{
public string Host { get; set; }
public int Port { get; set; }
public string Database { get; set; }
public int Timeout { get; set; }
}
我们将把连接数据存储在appconfig.json中,并使用RethinkDbOptions对象将数据注入RethinkDbConnectionFactory。RethinkDbConnectionFactory将为我们的应用程序提供与 RethinkDB 集群的持久连接:
public class RethinkDbConnectionFactory : IRethinkDbConnectionFactory
{
private static RethinkDB R = RethinkDB.R;
private Connection conn;
private RethinkDbOptions _options;
public RethinkDbConnectionFactory(IOptions<RethinkDbOptions> options)
{
_options = options.Value;
}
public Connection CreateConnection()
{
if (conn == null)
{
conn = R.Connection()
.Hostname(_options.Host)
.Port(_options.Port)
.Timeout(_options.Timeout)
.Connect();
}
if(!conn.Open)
{
conn.Reconnect();
}
return conn;
}
public void CloseConnection()
{
if (conn != null && conn.Open)
{
conn.Close(false);
}
}
public RethinkDbOptions GetOptions()
{
return _options;
}
}
打开appsettings.json并添加 RethinkDB 集群连接数据:
"RethinkDbDev": {
"Host": "localhost",
"Port": 28015,
"Timeout": 10,
"Database": "TokenStore"
}
现在我们可以在Startup.cs中创建RethinkDbConnectionFactory的单例实例。由于RethinkDb连接是线程安全的,因此您应该在整个应用程序中重用相同的连接。
public void ConfigureServices(IServiceCollection services)
{
//....
services.Configure<RethinkDbOptions>(Configuration.GetSection("RethinkDbDev"));
services.AddSingleton<IRethinkDbConnectionFactory, RethinkDbConnectionFactory>();
}
在Startup.Configure方法中测试连接:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory,
IRethinkDbConnectionFactory connectionFactory)
{
//....
var con = connectionFactory.CreateConnection();
con.CheckOpen();
}
数据库初始化
TokenGen 应用程序逻辑涉及两个实体:令牌和颁发者。令牌由应用程序实例(颁发者)通过调用/api/token端点颁发给客户端。我们将创建一个数据库来存储这两个条目。
首先我们为每个实体创建一个类:
public class Issuer
{
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public DateTime Timestamp { get; set; }
}
public class Token
{
[JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; set; }
public DateTime Expires { get; set; }
public string Issuer { get; set; }
}
现在我们将创建一个使用 RethinkDb 连接工厂并实现数据库初始化逻辑的服务:
public class RethinkDbStore : IRethinkDbStore
{
private static IRethinkDbConnectionFactory _connectionFactory;
private static RethinkDB R = RethinkDB.R;
private string _dbName;
public RethinkDbStore(IRethinkDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
_dbName = connectionFactory.GetOptions().Database;
}
public void InitializeDatabase()
{
// database
CreateDb(_dbName);
// tables
CreateTable(_dbName, nameof(Token));
CreateTable(_dbName, nameof(Issuer));
// indexes
CreateIndex(_dbName, nameof(Token), nameof(Token.Issuer));
CreateIndex(_dbName, nameof(Issuer), nameof(Issuer.Name));
}
protected <span class="hljs-keyword
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~