All posts by 龙生

ASP.NET Core 数据保护(Data Protection)【中】

前言 上篇主要是对 ASP.NET Core 的 Data Protection 做了一个简单的介绍,本篇主要是介绍一下API及使用方法。 API 接口 ASP.NET Core Data Protectio 主要对普通开发人员提供了两个接口,IDataProtectionProvider 和 IDataProtector。 我们先看一下这两个接口的关系:

可以看到,IDataProtector继承自IDataProtectionProvider ,并且提供了两个方法 Protect 和 Unprotect ,从命名来看,一个是加密,一个是解密。而他们的签名都是传入一个byte数组,这也就意味着他们可以加密和解密一切对象。返回的也是byte数组,也就是说在实际的使用过程中,我们应该自己添加或者使用系统的一些扩展方法来具体化我们的需求。 我们再看一下IDataProtectionProvider接口:

IDataProtectionProvider提供了一个方法,通过传入一个 purpose字符串(见后面详细介绍)来生成一个IDataProtector接口对象。 从这个接口的命名来看,它以Provider结尾,也就是说这部分我们可以实现自己的一套加解密的东西。 我们在阅读微软项目的源代码的时候,经常看一些以xxxxProvider结尾的对象,那么它的职责是什么,同时扮演什么样的角色呢? 其实这是微软专门为ASP.NET设计的一个设计模式,叫Provider Model设计模式,也可以说它是由微软发明的,它不属于23种设计模式中的一种,从功能上来看的话,应该是工厂和策略的结合体。自ASP.NET 2.0开始,微软就开始引入这种设计模式,最开始主要是用于实现应用程序的配置的多个实现。比如开发者最熟悉的web.config中, 针对于数据库连接字符串的配置, 还有二进制,再比如XML啊等等很多,现在其他地方这种模式也用的越来越多起来。 再来说一下CreateProtector方法签名中的 purpose 这个字符串,在上一篇博文中为了读者好理解,我把传入的purpose说成可以理解为一个公钥,其实这个说法是不严谨的,可以理解为一个标识,指示当前Protector的用途。 在使用IDataProtector的时候,会发现它还有一些扩展方法位于Microsoft.AspNetCore.DataProtection命名空间下:

可以看到,CreateProtector还提供了可以传多个purpose的方法(IEnumerable,params string[]),为什么会有这种需求呢? 其实DataProtector是有层次结构的,再看一下IDataProtector接口,它自身也实现了IDataProtectionProvider接口,就是说IDataProtector自身也可以再创建IDataProtector。 举个例子:我们在做一个消息通讯的系统,在消息通讯的过程中,需要对用户的会话进行加密,我们使用CreateProtector("Security.BearerToken")加密。但是加密的时候并不能保证消息是不受信任的客户端发过来的,所以想到了CreateProtector("username")来进行加密,这个时候假如有一个用户的用户名叫“Security.BearerToken”,那么就和另外一个使用Security.BearerToken作为标示的 Protector 冲突了,所以我们可以使用 CreateProtector([ “Security.BearerToken”, “User: username” ])这种方式。它相当于 provider.CreateProtector(“Security.BearerToken).CreateProtector(“User: username”)。 意思就是先创建一个Protector叫“Security.BearerToken”,然后再在purpose1下创建一个名为“User: username”的Protector。 用户密码哈希 在Microsoft.AspNetCore.Cryptography.KeyDerivation命名空间下提供了一个KeyDerivation.Pbkdf2方法用来对用户密码进行哈希。 具有生命周期限制的加密 有些时候,我们需要一些具有过期或者到期时间的加密字符串,比如一个用户在找回密码的时候,我们向用户的邮箱发送一封带有重置命令的一封邮件,这个重置命令就需要有一个过期时间了,超过这个过期时间后就失效,在以前我们可能需要向数据库存储一个时间来标记发送时间,然后再解密对比和数据库的时间差来验证。 现在我们不需要这么做了,ASP.NET Core 默认提供了一个接口叫 ITimeLimitedDataProtector ,我们先看一下这个接口的定义:

ITimeLimitedDataProtector提供了数个重载方法用来设定带有生命周期的加密方法,用户可以通过Date TimeOffset,TimeSpan等参数来设置时间。 有对应的加密,就有相对应的解密方法,在这里就不详细介绍了。有兴趣的同学可以去看一下官方文档。 配置数据保护 在我们的 ASP.NET Core 运行的时候,系统会基于当前机器的运行环境默认配置一些关于 Data Protection 的东西,但是有些时候可能需要对这些配置做一些改变,比如在分布式部署的时候,在上一篇博文的末尾也提到过,下面就来看一下具体怎么配置的吧。 上篇文章已经提到过,我们通过以下方式来把 Data Protection 注册到服务中:

其中AddDataProtection 返回的是一个 IDataProtectionBuilder 接口,这个接口提供了一个扩展方法PersistKeysToFileSystem() 来存储私钥。可以通过它传入一个路径来指定私钥存储的位置:

可以传入一个共享文件夹,来存储私钥,这样在不同机器的私钥就可以保存到一个位置了。可以通过此种方式在分布式部署的时候,隔离开了机器的差异化。 如果你觉得不安全,还可以配置一个X.509证书来,进行加密:

上篇文章讲过,Data Protection 的默认保存时间是90天,你可以通过以下方式来修改默认的保存时间:

默认情况下,即使使用相同的物理密钥库,Data Protection 也会把不同的应用程序隔离开,因为这样可以防止从一个应用程序获取另外一个应用程序的密钥。所以如果是相同的应用程序,可以设置相同的应用程序名称:

有时候需要禁用应用程序生成密钥,或者是说我只有一个程序用来生成或者管理密钥,其他程序只是负责读的话,那么可以这样:

修改加密算法 可以使用UseCryptographicAlgorithms方法来修改ASP.NET Core […]

龙生   16 Sep 2017
View Details

ASP.NET Core 数据保护(Data Protection)【上】

前言 上一篇博客记录了如何在 Kestrel 中使用 HTTPS(SSL), 也是我们目前项目中实际使用到的。 数据安全往往是开发人员很容易忽略的一个部分,包括我自己。近两年业内也出现了很多因为安全问题导致了很多严重事情发生,所以安全对我们开发人员很重要,我们要对我们的代码的安全负责。 在工作中,我们常常会见到 encode,base64,sha256, rsa, hash,encryption, md5 等,一些人对他们还傻傻分不清楚,也不知道什么时候使用他们,还有一些人认为MD5就是加密算法。 在 ASP.NET Core 中,为数据保护相关提供了一批新的 API,包括加密解密机制,下面就让我们来看看吧。 目录 加密,编码,哈希之间的区别 数据保护(Data Protection)介绍 ASP.NET Core 中的数据保护 总结 编码,加密,哈希之间的区别 编码 编码是信息从一种形式或格式转换为另一种形式的过程,他们是可逆的。 如 url、base64、jsunicode、utf-8等等。 加密 加密是可逆的,类似于编码也是把数据从一种形式转换为另一种形式,它通过一个特定的加密的密匙,相对应的有解密的过程。加解密的算法有2种:对称加密算法和非对称加密算法。 对称:DES、AES、SM1、RC4 等等。 非对称:RSA、ECC、SM2 等等。 哈希 又叫"散列",就是把任意长度的数据转换成固定长度的“指纹”,这个过程是不可逆的。而且只要输入发生改变,输出的 hash值也会有很大不同。 它还有一个特性是相同的输入总是有相同的结果, 这种特性恰好合适用来用来保存密码。 如:MD5、SHA256, SHA512, RipeMD, WHIRLPOOL等等。 数据保护(Data Protection)介绍 在看数据保护官方文档的时候,微软的文档是这样写的,大致意思就是他们基于几点需求,要开发一套数据保护的库以便用来给受信任的客户端和不受信任的客户端来使用。这几点要求就是: 1、真实性、完整性 举了一个身份验证cookie的例子,就是服务端生成了一个包含xyz权限的token,然后会在将来的某个时间过期,这个时候就需要重新请求生成一个,怎么样来保证请求的token不是被篡改过的。 2、机密性 服务器要保证请求是受信任的,所以就需要一些包含特定操作环境的信息,比如一个路径,一个权限或者一个句柄或者其他的一些东西特定于服务器的东西,这些信息不应该透漏给不受信任的客户端,也就是说类似于私钥。 3、隔离性 然后就是要求做成一个组件,并且这个组件具有独立性,可以不依赖于系统中的其他组件。如一个bearer token的组件,它要使用这个组件的话,也不需要引用anti-CSRF这种机制了。 再进一步的缩小需求范围,加密的数据不需要在系统之外的其他系统中使用,另外处理速度要尽可能的快,因为每一次web请求都会使用加密组件一次或者多次。 基于以上要求,微软提出来可以使用密码学,因为这是一个典型的密码学应用的场景。确实这是一个密码学的应用场景,并且是一个非对称加密算法的场景。但是大家都知道,非对称加密是由一个公钥和私钥用来保证安全性的,即使公钥遭泄露,整个通讯仍然是安全的,这就是它比对称加密的好处。但是非对称加密也是有缺点的,就是加密和解密花费的时间长,速度慢。 但是上面的要求又是需要速度尽可能快,怎么办呢? 于是微软的工程师们想出了可以通过精简并且优化非对称加密机制,来达到这个要求。因为不需要跨系统或者跨语言什么的,所以也不需要什么协议之类的,这就给优化带来了更多的可能性。 到这里,我就想,如果让我来基于以上几点来设计开发这样一个系统,我应该怎么样设计?怎么样达到要求? 带着这个问题,我们来进一步看看微软是怎么样做的吧? 下面是一些总结的设计原则 : 1、配置应该尽量的简单,默认情况下应该可以零配置,开发人员可以直接运行。 2、提供一个简单的API,应该容易使用,并且不会轻易用错。 3、开发人员不需要专门学习怎么样管理这些钥(公钥,私钥),系统应该自动的选择算法和管理钥的生命周期。理想情况下开发人员都不应该访问这些钥的原始文件。 4、钥应该是受保护的,不会被远程调用到。系统应该有一个自动保护机制并且可以自动应用。 如果让我设计这样一个库,我可能不会想到这么多,也许只会想到前3点。 再看一下针对的受众群体: 1、应用程序开发人员和框架开发人员(不需要学习任何知识)。 2、应用开发人员和系统管理员(不使用默认配置,只是设定一些路径等)。 3、针对具有更高安全意识的开发人员提供可扩展api,或特定需求扩展(需要重写系统的组件,有一些独特的需求)。 以上,可以看到微软在开发一个组件的时候对问题的分析,也许我们可以从中学到一些东西。 ASP.NET Core 中的数据保护 Web应用程序中经常需要存储一些敏感数据(如用户密码),Windows 系统为桌面程序提供了DPAPI用来使用,但是并不适用于 Web 系统。ASP.NET Core提供了一套简单易用的API 用来保护数据。 ASP.NET Core 中,数据保护主要是用来给服务端设计的,用来替换ASP.NET 1.x-4.x中的,machineKey主要是用来保证使用Form身份验证时Cookie数据的加密解密,以确保不会被修改。或者ViewState数据的加密解密不被篡改,以及对session状态标识进行验证。 先看一下最简单的使用方法: […]

龙生   16 Sep 2017
View Details

十二个 ASP.NET Core 例子

原文地址:http://piotrgankiewicz.com/2017/04/17/asp-net-core-12-samples/ 作者:Piotr Gankiewicz 翻译:杨晓东(Savorboard) 前言 在今天的博客中,我将介绍十几个可以在 ASP.NET Core 应用程序中使用的简单示例。从最简单的东西开始,比如 Options, 中间件,数据库,甚至 Nginx 或者 Docker。 首先确定你已经执行过了 dotnet restore , 然后运行 dotnet run 来启动应用程序,如果该示例正在使用比如像数据库这样的外部资源的话,请确保你已经安装并且运行它。 #1. Options 我们先看一下 options 来热个身,你可以很轻松的创建一个被叫做 XyzOptions 的类并且将其绑定到 appsettings.json 文件,来做一个配置的定义,并且通过注入 IOptions 来使用它的实例。 #2. 中间件 你可以通过将自己的 中间件 填加到整个流程中来扩展Http请求管道。如果你曾经使用过像NodeJS这样的框架,并且想要使用自己的代码来验证或者处理传入的请求,那么你也可以在 ASP.NET Core 中执行此操作。 #3. 过滤器 需要定制异常处理程序? 需要记录传入的请求或者验证他们? 通过使用 过滤器 ,只需创建一个新 Attribute 并且在 MVC Controller 上使用他们就可以实现这些功能或者更多的一些功能。 #4. Autofac 在 ASP.NET Core 中,依赖注入和 IOC 容器已经是内置的框架,但是你仍然可以使用自己喜欢的库来替换他们,比如你可以使用 Autofac 来帮助你提供更多依赖倒置原则方面的功能。 #5. Tests 我们都知道怎么样编写一个好的单元测试,但是真的是对的吗? 那么集成测试(端到端)呢? 当然你可以公开你的 API 实例,并且通过 HTTP Client 来执行 HTTP 请求。 然而,有一个更好的办法,你可以在内存中运行这样的测试,感谢 TestHost 这个库。 #6. SQL Server 你知道你可以在 Linux 上运行 SQL Server 了吗? 不管怎么说,你可以比如使用 Entity Framework Core 库通过 .NET Core 创建一个 SQL Server 实例, 但是,我更喜欢更加轻量级的解决方案,因此实例提供的代码使用的是 Drapper。 #7. MongoDB 你喜欢使用像我用的这种 NOSQL 数据库吗? 你可以使用 MangoDB 驱动程序,并且从 .NET Core […]

龙生   16 Sep 2017
View Details

如何在 ASP.NET Core 中发送邮件

前言 我们知道目前 .NET Core 还不支持 SMTP 协议,当我么在使用到发送邮件功能的时候,需要借助于一些第三方组件来达到目的,今天给大家介绍两款开源的邮件发送组件,它们分别是 MailKit 和 FluentEmail , 下面我对它们分别进行介绍。 MailKit 在 ASP.NET Core 中,可以使用 MailKit 来发送邮件,它支持跨平台,并且支持 IMAP, POP3, SMTP 等协议。 你可以使用下面的方式安装:

下面是一个简单的发送邮件的例子:

如果你要发送的 Body 内容是 HTML 的话,你可以使用下面这种:

Fluent Email Fluent Email 这个也是一个开源项目,利用它,你可以使用 Razor 模板来发送邮件,并且可以集成一些第三方的邮件发送程序比如 Mailgun等,但是此包只在 .NET 4.6 下才支持 SMTP 。你可以使用如下命令来安装它:

你可以使用最基本的方式来发送邮件,很简单如下:

或者,你可以使用 Razor 模板来发送:

Email.DefaultRenderer 是告诉FulentEmail 使用哪个渲染器(你也可以自己实现一个自己的),然后提供了一个 template 模板,内容为 Razor 语法的模板字符串,然后使用 UsingTemplate 来进行渲染呈现。 磁盘上的 cshtml 模板 加入你的邮件 Razor 模板文件比较大,用字符串来表示的话不太优雅,那么你可以把模板文件放到磁盘上,然后使用如下方式来加载:

使用 Mailgun 发送邮件 可能有一些人对 Mailgun 还不太清楚,Mailgun 是国外的一个邮件服务公司,比如著名的 Github 的邮件服务就托管在它的上面,免费的 Maingun 账户每个月可以发送 10000 封邮件,对于很多中小网站足够用了。 当使用 Mailgun 来发送邮件的时候,你首先需要去注册一个账号,然后可以利用 Mailgun 提供的 Rest API 来管理发送或者接收的邮件。使用 FluentEmail 集成的 Mailgun只需要添加如下包:

注册完 Mailgun 之后会给你分配一个 API Key […]

龙生   16 Sep 2017
View Details

EF Core 2.0 新特性

前言 目前 EF Core 的最新版本为 2.0.0-priview1-final,所以本篇文章主要是针对此版本的一些说明。 注意:如果你要在Visual Studio 中使用 .NET Core 2.0 , 你需要至少 Visual Studio 2017 15.3 预览版本。 安装或升级到 EF Core 2.0 你可以通过以下命令来安装或者升级你目前的 .NET Core 版本。

工具包

EF Core 2.0 新功能 改进的 LINQ 翻译 避免创建不必要的子查询 一些命令将切换到客户端进行执行 只有少数请求才会检索表的所有列 有事没有适当的过滤条件,将单个LINQ 查询转换为 N + 1 查询。 EF.Functions.Like() 在 EF Core 2.0 中添加了 EF.Functions 属性,EF Core Provider 可以使用它们来自定义一些映射到数据库函数后者运算符的方法,以便于在 LINQ 查询中调用它们。如:

分离实体和表 分离实体和表什么意思呢?在以前,一个数据库表会映射到 EF 中的一个实体对象,也就是表和实体是一一对应的关系。那么在 2.0 版本中,允许映射一些关联的实体到一个表中,并且EF会维护这些实例或者引用关系。

在生成数据库表的时候,Customer和 Address 将生成为一个表。 注意:priview1 中此功能暂不完整。 全局查询过滤 新版本引入了一个叫做“垂直过滤”的一个功能,这是一个比较常见的需求。 在我们定义EF Core上下文模型的时候,可以在模型创建的时候附加一些过滤条件,比如在查询的时候总是过滤掉一些“逻辑删除”的数据。

当通过直接查询或者导航属性(Include())查询类型数据时,将会自动应用此过滤条件。当然你可以使用 IgnoreQueryFilters()来在查询中禁用此全局过滤器。 DbContext 连接池 通常在 ASP.NET Core 中使用 EF Core 会涉及到自定义的 DbContext,然后注入到系统容器中,再通过 Controller 的构造函数从容器中来获取该对象实例。这也就意味着在每个请求中都会创建一个新的实例。 在EF […]

龙生   16 Sep 2017
View Details

分布式事务,EventBus 解决方案:CAP【中文文档】

前言 很多同学想对CAP的机制以及用法等想有一个详细的了解,所以花了将近两周时间写了这份中文的CAP文档,对 CAP 还不知道的同学可以先看一下这篇文章。 本文档为 CAP 文献(Wiki),本文献同时提供中文和英文版本,英文版本目前还在翻译中,会放到Github Wiki 中。 目录 前言 1、Getting Started 1.1 介绍 1.2 应用场景 1.3 Quick Start 2、API接口 2.1 发布/发送 2.1.1 事务 2.2 订阅/消费 2.2.1 例外情况 3、配置 3.1 Cap Options 3.2 RabbitMQ Options 3.3 Kafka Options 3.4 SqlServer Options 3.5 MySql Options 4、设计原理 4.1 动机 4.2 持久化 4.3 通讯数据流 4.4 一致性 5、实现 5.1 消息表 5.2 消息格式 5.3 EventBus 5.4 重试 6、分布式事务 6.1 异步确保 7、FAQ 1、Getting Started 1.1 介绍 CAP 是一个遵循 .NET Standard 标准库的C#库,用来处理分布式事务以及提供EventBus的功能,她具有轻量级,高性能,易使用等特点。 目前 CAP 使用的是 .NET Standard 1.6 的标准进行开发,目前最新预览版本已经支持 .NET Standard 2.0. 1.2 应用场景 […]

龙生   16 Sep 2017
View Details

.NET Core 事件总线,分布式事务解决方案:CAP

背景 相信前面几篇关于微服务的文章也介绍了那么多了,在构建微服务的过程中确实需要这么一个东西,即便不是在构建微服务,那么在构建分布式应用的过程中也会遇到分布式事务的问题,那么 CAP 就是在这样的背景下诞生的。 最初打算做这个东西是在去年(2016)年底,最初是为了解决分布式系统中的分布式事务的问题,然后当时有了一个大概的概念轮廓,当时我对于前面两篇文章中关于异步消息和微服务之间通讯还不是太了解,只是觉得这样能够解决这一系列的问题,然后就着手做了,最后发现和这些概念竟然不谋而合。 经过大半年的不断重构以及修改,最终 CAP 1.0 版本发布了。作为一个开源项目,最初项目是在我的个人Github下,然后于上个月已经贡献给了 .NET China Foundation 组织,目前该项目由我和 DotNetCore 项目组共同维护。 CAP 介绍 Github:https://github.com/dotnetcore/CAP 开源协议:MIT CAP 是一个在分布式系统中(SOA,MicroService)实现事件总线及最终一致性(分布式事务)的一个开源的 C# 库,她具有轻量级,高性能,易使用等特点。 你可以轻松的在基于 .NET Core 技术的分布式系统中引入CAP,包括但限于 ASP.NET Core 和 ASP.NET Core on .NET Framework。 CAP 以 NuGet 包的形式提供,对项目无任何入侵,你仍然可以以你喜爱的方式来构建分布式系统。 CAP 具有 Event Bus 的所有功能,并且CAP提供了更加简化的方式来处理EventBus中的发布/订阅。 CAP 具有消息持久化的功能,也就是当你的服务进行重启或者宕机时,她可以保证消息的可靠性。 CAP 实现了分布式事务中的最终一致性,你不用再去处理这些琐碎的细节。 CAP 提供了基于 Microsoft DI 的 API 服务,她可以和你的 ASP.NET Core 系统进行无缝结合,并且能够和你的业务代码集成支持强一致性的事务处理。 CAP 是开源免费的。CAP基于MIT协议开源,你可以免费的在你的私人或者商业项目中使用,不会有人向你收取任何费用。 Getting Started 目前, CAP 同时支持使用 RabbitMQ 或 Kafka 进行底层之间的消息发送,你不需要具备 RabbitMQ 或者 Kafka 的使用经验,仍然可以轻松的集成到项目中。 CAP 目前支持使用 MS Sql Server 数据库的项目,其他数据库正在支持中… CAP 同时支持使用 EntityFrameworkCore 和 Dapper 的项目,你可以根据需要选择不同的配置方式。 下面是CAP在系统中的一个不完全示意图: 图中实线部分代表用户代码,虚线部分代表CAP内部实现。 下面,我们看一下 CAP 怎么集成到项目中: […]

龙生   16 Sep 2017
View Details

微服务中的异步消息通讯

前言 在上一篇文章中,我们说到了异步消息通讯,下面这篇文章呢,大部分内容是翻译来自于这篇微软的文章,所以其内容还是具有一定的理论指导意义的。 当我们跨多个微服务进行内部通讯的时候,异步消息和事件驱动至关重要。我们可能需要在不同的边界上下文中进行域模型的更新。 我们举个例子,比如 eShop 这个项目中,Ording 服务在下单的时候要和 Catelog 服务进行通讯进行库存的扣减操作,这个时候我们就需要一种方式来做这个事情,并且能够在发生故障的时候也能正常工作,也就说需要进行基于异步消息和最终一致性的通讯方式。 当使用基于消息的通讯方式的时候,进程中是采用的异步的方式通讯的。客户端向某个服务发送消息,如果这个消息需要回复,那么另一个服务会向客户端发送一个不同的消息,并且客户端会认为该消息不会立即被接收到,并且不存在响应,这就是一种基于消息的通讯方式。 消息由标题(name 或者 title)和内容(Body)共同构成。消息通常会通过一些异步协议进行发送(如AMQP,kafka协议)。 异步消息通讯有两种:一种是单接收者(端到端),另外一种是多接收者(广播)。 如果有同学对消息队列比较了解的话,这就是消息队列的两种典型使用方式。 基于消息的单接收者 单接收者也就是说是点到点的通讯,将消息使用队列等方式从一点发送的另外一点,并且该消息仅会被处理(消费)一次。这中间一个特殊情况就是,当队列在尝试从故障中恢复时候,有可能会多次发送相同的消息,客户端必须实现幂等性以便能够处理相同的消息一次。 单接收器消息通讯的方式适用于将异步命令从一个微服务发送到另一个微服务。如下图: 一旦开始使用了基于消息的通讯,你应该避免将基于消息的通讯和同步的HTTP通讯混合起来。 注意:当command来到客户端应用程序时候,它们可以实现为HTTP的同步命令。当你需要更高的可扩展性或者你业务流程中已经使用了基于消息的方式时,那么你就应该使用基于消息的通讯方式。 基于消息的多接收者 多接收者是消息通讯中一种更加灵活的方式,你可能还需要使用 发布/订阅 这种机制,以便于接收来自发送方或者其他微服务或者外部应用程序的消息。 这样,将来可以添加更多的其他消费者用户,而无需修改发送方的服务代码。 当你使用发布/订阅这种通讯方式的时候,在发送端和订阅端你也许会用到事件总线的接口。 异步事件驱动通讯 当使用异步事件驱动通信时, 一个微服务当域模型发生更新时,会发布一个集成事件,然后另外一个微服务可能需要关注这个事件,比如 eShop 中,当 product catelog 微服务发生一个价格变动的时候。另外的微服务需要订阅这个事件,这样就可以以异步的方式来接收这个事件。然后当事件触发的时候,订阅端就可以更新自己的 Domain Model,从而集成发送端的事件。 事件总线(Event Bus)可以设计为一个抽象类或接口,集成API 订阅或取消订阅事件和发布事件。事件总线还可以有一个或多个实现基于任何进程间消息传递代理,像一个消息队列或服务总线支持异步通信和发布/订阅模型。 如果事件驱动中集成了最终一致性,那么用户应该清楚这种行为,客户端用户及其业务必须显式地拥抱最终一致性并且意识到在许多情况下这种业务没有任何问题。 你可以跨越多个微服务来集成事件驱动,这些服务之间拥有最终一致性。 一个最终一致性的“事务”可能是由多个分布式的事件操作组成的一个集合。在每一个事件中,相关的微服务都在更新自己的领域实体并且发布另外一个需要集成的事件到Eventbus中。 很重要的一点是 , 你可能需要多个微服务订阅一个事件。因此, 您可以使用基于事件驱动的发布/订阅消息模式的消息通讯, 如下图所示。这种发布/订阅的机制不是微服务独有的。它类似于DDD中边界上下文之间的通讯方式, 或者类似于CQRS架构中的从写库更新数据到读库的这种模式。它最终的目标是在整个分布式系统多个数据源之间的保持最终一致性。 你将实现基于消息的事件驱动通信协议。AMQP可以帮助实现可靠的排队通信。 当您使用事件总线时,您可能希望使用的是抽象级别的东西(如Eventbus interface),它使用类似于 RabbitMQ 或服务总线(如Azure Service Bus及 Topic)来作为底层,然后提供相关API。或者,您可能希望使用更高级别的服务总线,如NServiceBus,MassTransit或Brighter来作为Eventbus和发布/订阅系统。 关于生产环境中的消息通讯技术 在消息通讯技术中,实现抽象级别的事件总线是存在不同的级别的。例如,像RabbitMQ 和Azure Event Bus这样的产品比其他产品(如NServiceBus,MassTransit或Brighter)级别就更低一些,NServiceBus这些他们可能基于底层的这些之上,当然后者也更加的重量级。 但是很多时候,我们可能学习这些重量级的东西需要花费很多的成本,而且我们也用不到那么重量级的东西,正如在eShopOnContainers示例中所做的那样,在Docker容器上运行的RabbitMQ之上的简单实现可能就足够了。 但是,在生产系统中对于需要可扩展性的关键型任务,您可能需要进行评估一下。 为了使分布式应用程序开发更容易的并且提供高级抽象的功能,我们建议您评估其他商业和开源的服务总线,如NServiceBus,MassTransit和Bright。当然,您可以在像RabbitMQ和Docker这样的低级技术的基础上构建自己的服务总线功能。但是,这种工作对于企业应用来说可能花费的太多。 异步消息解决方案 到这里,我们会发现,我们真的是太需要这么样一个组件来帮助我们实现这些东西了,既能提供高抽象级别的API帮助我们简化操作,又能轻量级并且容易学习和集成到项目中,并且能够帮助我们解决分布式事务中的一致性问题,如果是开源免费的,那就更好了。 然后,重点来了~ 请期待下一篇,异步消息,分布式事务解决方案:(保密脸^_^)… 你可以关注一下博主,会第一时间收到通知哦~ 放心不会太久。 本文地址:http://www.cnblogs.com/savorboard/p/microservice-eventbus.html 作者博客:Savorboard 欢迎转载,请在明显位置给出出处及链接

龙生   16 Sep 2017
View Details

我眼中的ASP.NET Core之微服务 (二)

前言 接上一篇。 上一篇未完待续的原因是当时刚好是6-30号晚上马上12点了还没写完,然后我想赶在7月1号之前发出去,所以当时就发了。然后在发的时候出了一点问题,结果发出去的时候刚好是 7.1号 00:00分,所以就很尴尬~~ 这一篇,我们就接着说一说微服务吧。 接上文 第四步,重构。 当你写完代码之后,我认为有一个比较重要的步骤就是对写的代码进行一番重构,重构一般从两方面下手,第一方面是代码的命名以及格式,第二方面是代码的组织结构。 针对于代码命名以及格式的重构其实是有方法和技巧的,比如方法的命名以及方法的拆分等可以从<<重构>>这些书中来获取一些指导意见等,对于代码格式的话基本上现代的IDE都提供了很好的格式化工具,使用便是。 针对于组织结构的重构有时候是需要依赖很多你的经验的,经验丰富的程序员知道如果的去对写过的代码进行抽象,然后利用某种设计模式或者是面向对象的原则来让代码更加的利于维护和扩展,这种技能往往更难掌握,需要你去阅读很多的别人优秀的代码,然后去思考和学习。 OK,以上就是在构建单个微服务程序的个人总结的一些指导原则吧。 部署方式 指导原则可以帮助我们在构建系统的时候使其保持一个良好的结构,但是你还需要从整体上来把控整个微服务的布局。什么意思呢? 我们知道,微服务最良好的部署方式就是使用 Docker 容器进行部署,因为这样便于管理和配置。 在以前的单体结构的项目中也可以使用Docker进行整块的部署,我们可能部署到多个容器中,然后前置一个负载均衡器进行路由的转发,这样也是可以的。 通常情况下,即使我们的程序架构风格不是微服务,那么在组织代码结构时,也会进行模块的划分,比如划分为会员,商品,库存等。下面是一个单体应用整块部署使用Docker的部署图: 但是这种模式其实与容器的初衷是有一点违背的,容器所倡导的是一个容器只做一件事情。整块部署有一个明显的缺点是,如果随着应用程序的扩展那么每次代码的修改都要全部进行重新发布,但是我们经常修改的代码可能就是某一快的功能,而另外一些代码则永远不会动,这样不但发布程序的时候发布包很大,也容易出错,出问题造成的影响也比较广。 比如,在一个电商网站中,有一些模块是经常发生变化的,比如一些促销,产品等页面,这些页面的访问量也很大,而另外一些页面比如用户中心积分查看,历史订单查看这些功能则不会经常变动,并且访问量要小很多。那么如果他们都在一个系统中,势必会引起这些问题:1、性能优化,如果访问量很高的模块出现性能问题,那么你只能针对整个程序进行扩展部署,而不是单个模块。2、测试,由于模块的依赖,那么在修改一块地方的时候,必须重新对整个应用程序进行一次测试,并且重新部署所有这些实例。3、无法进行扩展,你无法简单的进行接口或者服务的扩展,这会使SOA变得很困难。 那么我们就再顺便说一下SOA,我们知道大多数的公司在 .NET FX 时代使用 WCF 技术进行项目的 SOA 化,比如常见简单的会使用 SOAP ,HTTP,MQ等进行通讯,他们也会把系统进行划分(子系统)和分层。听起来可能和微服务有点像,那么他们有什么区别呢? 想必这是一个很多人讨论过的话题,那么直接说结论吧。 微服务它来自于SOA,但是和SOA不同的是它并没有那么重量级,什么意思呢?比如它没有SOA中的像集群的Broker, 那么大的组织的划分,中央负责人, 还有企业服务总线 (ESB)等。 然后就是我们的主题微服务,微服务架构的定义就是一组小型的服务。每一个服务都位于自己的进程中,并且使用诸如HTTP, WebSockets,或者 AMQP 之类的协议进行通讯。它很小,并且专注于做好一件事,这个很重要,它看起来像OOP中的单一职责原则,如果你2周之内不能完成一个微服务模块,那么可能你对于边界划分出了点问题。 关于微服务的优缺点不做过多的介绍了,有兴趣的同学可以看一下在我博客里面的 Martin Fowler 的 这篇文章。 这篇文章提到了『微服务设计』这本书,如果你想对微服务有更多了解的话可以看一下这本书,建议购买。 微服务中的一些技术挑战 下面需要说的是个人对于在构建微服务的过程中会面临的一些问题,或者说叫做挑战吧。 1、微服务的边界怎么定义。 上一篇文章已经提到过了,在定义微服务边界的过程中,DDD中的指导原则会帮助你大忙。 这可能是你在构建微服务过程中遇到的第一个难题,一个良好的微服务能够对其他微服务尽可能少的依赖,同一个应用程序中你需要用不同的上下文进行解耦,每个上下文有可能是使用不同的程序语言的。这些上下文应该被独立的定义和管理。比如一个User,在 Identity 上下文可能是一个用户,在 CRM 中是一个客户,在订单上下文是一个买家,等等。 2、如何跨微服务进行查询。 因为我们已经微服务化了,所以我们的应用程序数据可能分布在不同的数据库中,那么如何实现从多个为微服务器数据库中查询数据成为一个难题了。 比如,我们前台的数据展示页面需要一个销售统计的报表,其中的数据分别来源于订单,库存和商品。那么我们应该怎么样来处理这种复杂性呢? 目前流行的解决方案有以下几种: API网关。 使用API网关来对多个微服务器的数据库进行聚合。 但是在实现这种模式的时候你需要非常的小心,它有可能是你系统中性能的瓶颈,甚至它有可能违背微服务的自治原则。为了尽可能避免这个陷阱,你需要设计多个细粒度的 API 网关,每个网关关注系统一个垂直领域的“切片”区域,或者是一个业务领域。现在大部分的云提供商都提供的有 API 网关相关服务,比如AWS的 Amazon API Gateway,Azure 的 Establish API Gateways 等,借助于这些服务可以方便的对 API 进行管理。 CQRS与读表。 不知道大家有没有听说话物化视图(Materialized View)这个名词。你可以理解为远程视图,使用这种方法,你可以提前准备好一个只读表,其中包括多个微服务的数据,这个只读表的结构和你展示给客户的页面数据是对应的。 那么有同学可能会存在这样一个问题,假如我基于不同的数据库建立一个物化视图,那么在我建立物化视图的过程中,我应该怎么样进行查询,因为对于单个数据库的查询可能仍然是复杂的。确实如此,在以前单个应用程序的时候,我们在呈现个客户端需要的数据的时候,可能会是一个复杂的SQL Join连接查询的结果。那么这里的解决方案就是,我们需要建立一个和我们业务无关的一个单独的数据库,然后这个数据库中会包含一些和界面上需要的数据进行一一对应的一些查询用的表,然后我们应用程序中引入 CRQS 这种模式,将需要的数据写入到这些查询表中。 这不仅解决了跨微服务查询这个难题,并且也提高了性能。但是引入CQRS也就意味着你需要拥抱最终一致性。 数据中心的 “冷数据”。 对于一些不需要做实时数据的复杂查询或者报表,通常是将微服务的“热数据”作为“冷数据”导出到数据中心以供报表。这个数据中心可能是一个基于大数据的系统,比如 Hadoop,AWS的Redshit,Azure的SQL Data warehosue等。 同步的过程你可以使用事件驱动这种通讯技术,或者是一些数据库提供的基础设施中的导入/导出工具等。如果使用事件驱动的话,其过程有点类似上面的CRQS查询过程。 3、如何实现多个微服务的数据一致性。 […]

龙生   16 Sep 2017
View Details
1 222 223 224 432