asp.net core 从单机到集群

asp.net core 从单机到集群

Intro#

这篇文章主要以我的活动室预约的项目作为示例,看一下一个 asp.net core 应用从单机应用到分布式应用需要做什么。

示例项目#

活动室预约提供了两个版本,集群版 和 单机版

单机版方便部署,不依赖其他环境,数据库使用的是 sqlite,详细部署文档可以参考:https://github.com/WeihanLi/ActivityReservation/blob/dev/docs/deploy/standalone.md

集群版,目前依赖的组件有 mysql(数据库)/redis(缓存)/elasticsearch(日志)

日志#

日志原来是输出到文件中的,单机部署没有什么问题,可以直接 ssh 到机器上查看文件内容,但是如果部署到集群上,日志再输出到文件的话,排查起来可就有点麻烦了,日志是分散在多台机器上,只看某一台机器上的日志可能并不能解决问题。

基于日志这个痛点让我把日志迁移到 elasticsearch 上,日志统一输出到 es,并通过 kibana 来搜索/分析日志。

日志组件一直用的 log4net,日志输出到 es ,自己写了一个 es 的 Appender, 但是后来越来越觉得 log4net使用起来不够灵活,后来日志组件换成了 serilog,使用 serilog 就可以方便的扩展,增加日志要记录的信息,关于自定义 serilog enricher 可以参考 Serilog 自定义 Enricher 来增加记录的信息

使用 es 来存储日志还有一个好处,就是搜索日志非常的快,而且借助 kibana 可以很方便的进行统计分析

拿上篇文章的图来借用一下,下面是 kibana 基于日志的 RequestIP 来绘制的前十个访问最多的 IP 地址

缓存#

单机部署为了不增加系统复杂度,不引入外部依赖,单机版使用的是 MemoryCache
集群部署,就需要引入分布式缓存,我选择的是 redis,redis 组件是基于 StackExchange.Redis 的,自己在其基础上封装了一些功能。

在我的这个示例应用中 redis 不仅仅做缓存,我还用 redis 的 hash 实现了一个类似于 asp.net 里 Application 的服务,还有 redis 的发布订阅来实现一个 eventBus 来异步处理公告的浏览记录。

#

单机环境下,我们用 lock 或者用信号量来实现资源在某一段时间内只能被一个请求拿到

多台机器环境下,我们需要一个分布式锁,上面引入了 redis,就用 redis 来实现一个分布式锁,分布式锁详细实现可以参考:
RedLock

使用方式如下:

Copy

using (var redisLock = RedisManager.GetRedLockClient($"reservation:{reservation.ReservationPlaceId:N}:{reservation.ReservationForDate:yyyyMMdd}"))
{
    if (redisLock.TryLock())
    {
        var reservationForDate = reservation.ReservationForDate;
        if (!IsReservationForDateAvailable(reservationForDate, isAdmin, out msg))
        {
            return false;
        }

        // ...
        return true;
    }
    else
    {
        msg = "系统繁忙,请稍后重试!";
        return false;
    }
}

DataProtection#

微软在 .net core 下引入了 DataProtection 来保护网站的数据,你也可以用它做一些数据保护,之前做了一个简单数据保护扩展,通过 Filter 来自动实现数据的加密/解密,详细信息可以参考 asp.net core 参数保护

默认 DataProtection 的key 是保存到文件的,可能你也注意到过在 asp.net core 应用启动的时候默认会有一条日志信息如下:

多台机器同时部署的话,key 基本上就是不一样的,这样数据就不会被认为是安全的。

举个栗子,我的应用有一个后台使用 cookie 认证,cookie 会使用 DataProtection 的 key 进行加密,使用默认的 DataProtection 时,多台机器上(实际是k8s的多个pod) 的key 是不一样的,这就导致我在后台登录了之后,进入后台之后刷新一下可能就又跳转到登录界面,这是因为生成的 cookie ,对于一个服务来说是有效的,但是对于其他服务来说是无效的(key 不同,没有办法解密成功,认证失败),所以集群部署的时候,DataProection 是必须要设置的,放在一个统一的地方管理,我们上面已经引入了 redis,所以就把 DataProtection 的 key 放在 redis 中去保存(redis 服务可以做高可用,即使 redis 服务挂了也会重新生成一个 key,不会有什么影响)

使用到的包 Microsoft.AspNetCore.DataProtection.StackExchangeRedis,配置方式:

Copy

// DataProtection persist in redis
services.AddDataProtection()
    .SetApplicationName(ApplicationHelper.ApplicationName)
    .PersistKeysToStackExchangeRedis(() => DependencyResolver.Current.ResolveService<IConnectionMultiplexer>().GetDatabase(5), "DataProtection-Keys")
    ;

获取用户IP#

集群部署的时候,会有网关/反向代理去转发请求,这时候直接通过 HttpContext.Connection.RemoteIpAddress 获取到的 ip 地址就会是网关/反向代理的地址,并不是实际用户的地址,一般的反向代理软件会将真实的用户IP放在 X-Forwarded-For 请求头中,转发到下游真正的服务器地址,你可以从请求中直接获取 X-Forwarded-For 请求头的值,也可以使用微软提供的 ForwardedHeaders 中间件,配置方式:

Copy

public void ConfigureServices(IServiceCollection services)
{
    // ...
    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
        options.ForwardLimit = null;
        options.ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.All;
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseForwardedHeaders();
    // ...
}

具体参数配置可以参考文档:https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.2

Memo#

其他还有一些上面并未提到,

比较常用的如 Session,如果要上集群的话,也应该有相应的分布式 session,这个应用没有用到 session,所以上面没有提(之前用极验验证码的时候有用,后来换成腾讯的验证码服务之后去掉了session)

文件上传,如果是存在本地的话,也不太合适,可能需要存在一个集中的文件服务器或者云端存储如 Azure Blob。。(网站里的公告模块的图片上传还没改,,,打算基于 github 或者 开源中国的码云实现一个 storage )

其他暂时没想到了,想到了再补充吧。

Reference#

原文地址:https://www.cnblogs.com/ExMan/p/11373895.html

时间: 2024-10-31 09:24:40

asp.net core 从单机到集群的相关文章

Kubernetes初探[1]:部署你的第一个ASP.NET Core应用到k8s集群

转自:https://www.cnblogs.com/RainingNight/p/first-aspnetcore-app-in-k8s.html Kubernetes简介 Kubernetes是Google基于Borg开源的容器编排调度引擎,作为CNCF(Cloud Native Computing Foundation)最重要的组件之一,它的目标不仅仅是一个编排系统,而是提供一个规范,可以让你来描述集群的架构,定义服务的最终状态,Kubernetes可以帮你将系统自动得达到和维持在这个状态

Greenplum源码编译安装(单机及集群模式)完整版

公司有个项目需要安装greenplum数据库,让我这个gp小白很是受伤,在网上各种搜,结果找到的都是TMD坑货帖子,但是经过4日苦战,总算是把greenplum的安装弄了个明白,单机及集群模式都部署成功,下面由我给大家分享一下整个部署过程,并小分析一下安装过程中遇到的各种坑. 首先,说一下我的环境,CentOS 7.2.1511,64位操作系统,全新安装,没有更新过 [[email protected] ~]# cat /etc/redhat-release CentOS Linux relea

codis 3.2单机安装环境集群

codis 3.2单机安装环境集群 一.软件环境 系统:centos 6.5 Jdk:jdk-8u111-linux-x64.gz go : go1.7.3.linux-amd64.tar.gz zookeeper: zookeeper-3.4.6.tar.gz 本机IP:172.16.40.131 软件下载地址: codis:https://github.com/CodisLabs/codis zookeeper:https://zookeeper.apache.org/ go:http://

Kafka单机、集群模式安装详解(二)

本文环境如下: 操作系统:CentOS 6 32位 JDK版本:1.8.0_77 32位 Kafka版本:0.9.0.1(Scala 2.11) 接上篇 Kafka单机.集群模式安装详解(一) 6. 单节点多Broker模式 Kafka使用可以有多种模式,包括单节点单Broker,单节点多Broker,多节点多Broker. 这里我们简单区分一下: 单节点单Broker:在单台机子上,启动了一个Kafka实例(上一篇就是这种模式). 单节点多Broker:在同一台机子上开启多个Kafka(类似H

zookeeper的安装与配置(单机和集群)

单机模式: 1.首先去官网下载zookeeper的包 zookeeper-3.4.10.tar.gz 2.用FTP文上传到/usr/local下 3.解压文件tar -zxvf zookeeper-3.4.10.tar.gz 4.在conf文件夹下新建zoo.cfg文件,或者使用里面自带的zoo_sample.cfg,重新cp zoo_sample.cfg  zoo.cfg zoo.cfg文件内容: 1 tickTime=2000 2 dataDir=/Users/zookeeper/data

java及spark2.X连接mongodb3.X单机或集群的方法(带认证及不带认证)

首先,我们明确的是访问Mongos和访问单机Mongod并没有什么区别.接下来的方法都是既可以访问mongod又可以访问Mongos的. 另外,读作java写作scala,反正大家都看得懂......大概? 1.不带认证集群的连接方法(JAVAscala): 首先是创建连接的方法,我们先声明一个client,然后指定访问的DB和collection: private lazy val mongo = new MongoClient("192.168.2.51", 27017) priv

apache2.4+tomcat7 单机垂直集群 64位 windows操作系统

随着现在服务器的廉价,大多数的生产环境内存大多都已经达到 16G,但是java的运行环境,最大只能停留在2G ,这样就造成了这台服务器资源的浪费,所以单机的垂直集群就显得太有必要!本文需要具备 windows操作基础以及javaEE基础 生产环境大多都是 linux操作系统,鉴于写博客的方便性,我只能在自己电脑专供的win7 64位的操作系统中展示这个集群的部署方法,当然了在 windows和linux 中部署集群大同小异,大家重点看方法和步骤即可,好啦,正式入题! 因为我本机是 64位操作系统

备忘zookeeper(单机+伪集群+集群)

#下载: #单机模式 解压到合适目录. 进入zookeeper目录下的conf子目录, 复制zoo_sample.cfg-->zoo.cfg(如果没有data和logs就新建):tickTime=2000 dataDir=/Users/apple/zookeeper/data dataLogDir=/Users/apple/zookeeper/logs clientPort=2180 参数说明:tickTime: zookeeper中使用的基本时间单位, 毫秒值.dataDir: 数据目录. 可

zookeeper安装和配置(单机+伪集群+集群)

#单机模式 解压到合适目录. 进入zookeeper目录下的conf子目录, 复制zoo_sample.cfg-->zoo.cfg(如果没有data和logs就新建):tickTime=2000 dataDir=/Users/apple/zookeeper/data dataLogDir=/Users/apple/zookeeper/logs clientPort=2180 参数说明:tickTime: zookeeper中使用的基本时间单位, 毫秒值.dataDir: 数据目录. 可以是任意目