每个人都在谈论微服务。行业资深人士可能会记住单片或基于SOA的解决方案是做事的方式。时代变了。新工具使开发人员能够专注于特定问题,而不会给部署或通常与隔离服务相关的其他管理任务增加过多的复杂性。选择使用合适的工具来解决正确的问题变得越来越容易。
在本系列文章中,我们将探讨微服务的世界,它如何帮助解决现实问题,以及为什么行业越来越多地将其作为标准的做事方式。在本系列中,我们将尝试解决与此方法相关的常见问题,并提供方便简单的示例。在本系列的最后,我们应该有一个完整的基于微服务的架构的框架实现。今天,我们将关注微服务以及它们与替代方案的比较。我们还将列出我们计划在以下帖子中讨论的问题。
更新:在第2部分中,我们讨论了API网关。
什么是微服务?
微服务是一个孤立的,松散耦合的开发单元,可以解决一个问题。这类似于旧的“Unix”做事方式:做一件事,做得好。诸如如何“组合”服务提供的任何事项的事项留给更高层或政策。这通常意味着微服务往往避免相互依赖:如果一个微服务对其他微服务有一个硬性要求,那么你应该问自己是否有意义将它们全部放在同一个单元中。
"A microservice is an isolated, loosely-coupled unit of development that works on a single concern."
“微服务是一个孤立的,松散耦合的开发单元,可以解决一个问题。”
微服务对开发团队特别有吸引力的是他们的独立性。团队可以自己处理问题或一组问题。这创造了许多开发人员青睐的有吸引力的品质:
- 自由选择合适的工具:您一直想要使用的是新的库或开发平台吗?你可以(如果它是适合这项工作的工具)。
- 快速迭代:第一个版本不是最理想的吗?没问题,版本2可以立即出门。由于微服务往往很小,因此可以相对快速地实现更改。
- 重写是一种可能性:与单片解决方案相比,由于微服务很小,重写是可能的。技术堆栈是错误的选择吗?没问题,切换到正确的选择。
- 代码质量和可读性:隔离开发单元的质量往往更高,新开发人员可以非常轻松地使用现有代码。
生产质量的微服务
现在我们知道微服务是什么,这里列出了在设计基于微服务的架构时需要记住的事项。如果这看起来太抽象,不要担心;我们将在整个系列文章中系统地处理所有这些问题。
必须以这样的方式实施跨领域关注,即微服务不需要处理有关其特定范围之外的问题的细节。例如,身份验证可以作为任何API网关或代理的一部分来实现。
数据共享很难。微服务倾向于支持可以直接更新的每服务或每组数据库。在为您的应用程序进行数据建模时,请注意这种处理方式是否适合您的应用程序。为了在数据库之间共享数据,可能需要实现处理数据库之间的内部更新和事务的内部过程。可以在许多微服务之间共享单个数据库;请记住,如果您需要在将来进行扩展,这可能会限制您的选择。
可用性:由于隔离和独立,需要对微服务进行监控,以尽早检测故障。在一个大型软件堆栈中,一个服务器可能会被忽视一段时间。在选择用于管理服务的软件堆栈时考虑到这一点。
进化:微服务往往快速发展。当专门团队处理特定问题时,可以快速找到新的更好的解决方案。因此,有必要考虑服务的版本控制。只要有客户需要使用旧版本,旧版本通常可用。较新版本以特定于应用程序的方式公开。例如,使用HTTP / REST API,微服务的版本可以是自定义标头的一部分,或嵌入在返回的数据中。说明这一点。
自动部署:现在微服务如此方便的全部原因是,从完全干净的环境部署新服务非常容易。请参阅Heroku,Amazon Web Services,Webtask.io或其他PaaS提供商。如果您要采用自己的内部方法,请记住,部署新服务或预先存在的服务版本的复杂性对于解决方案的成功至关重要。如果不以方便,自动的方式处理部署,您最终可能会达到一定程度的复杂性,这超出了该方法最初带来的好处。
相互依赖性:将它们保持在最低限度。处理服务之间的依赖关系有不同的方法。我们将在稍后的博客文章系列中进一步探讨它们。现在,请记住,依赖性是这种方法的最大问题之一,因此寻求将它们保持在最低限度的方法。
传输和数据格式:微服务适用于任何传输和数据格式;但是,它们通常通过HTTP上的RESTful API公开公开。任何适合您的信息的数据格式。 HTTP + JSON现在非常流行,但是没有什么可以阻止你使用协议缓冲区而不是AMQP。
把事情做正确
所有这些问题都可以系统地处理。我们将探索本系列文章中的技巧和模式来处理它们。以下是我们将来在帖子中讨论的内容:
- API代理
- 记录
- 服务发现和注册
- 服务依赖性
- 数据共享和同步
- 优雅的失败
- 自动部署和实例化
保持真实:样品微服务
现在,这应该很容易。如果微服务从开发团队的脑海中掏出这么多的包袱,写一个应该是小菜一碟,对吧?是的,在某种程度上。虽然我们可以编写一个简单的RESTful HTTP服务并将其称为微服务,但在本文中我们将通过考虑上面列出的一些事情来做到这一点(不要担心:在以下帖子中,我们将扩展此示例包括上面列出的所有问题的解决方案。
对于我们的示例,我们将从Sandrino Di Mattia的关于使用Flux进行调试的优秀帖子中选择后端代码。在Sandrino的帖子中,一个简单的express.js应用程序为React.js应用程序制作了后端。我们将采用后端并对其进行调整。您可以在此处查看原始后端代码。
Sandrino示例中的后端处理许多不同的问题:登录,身份验证,CORS,票证更新操作和查询。对于我们的微服务,我们将专注于一项任务:查询门票。看看这个:
var express = require('express'); var morgan = require('morgan'); var http = require('http'); var mongo = require('mongodb').MongoClient; var winston = require('winston'); // Logging winston.emitErrs = true; var logger = new winston.Logger({ transports: [ new winston.transports.Console({ timestamp: true, level: 'debug', handleExceptions: true, json: false, colorize: true }) ], exitOnError: false }); logger.stream = { write: function(message, encoding){ logger.debug(message.replace(/ $/, '')); } }; // Express and middlewares var app = express(); app.use( //Log requests morgan(':method :url :status :response-time ms - :res[content-length]', { stream: logger.stream }) ); var db; if(process.env.MONGO_URL) { mongo.connect(process.env.MONGO_URL, null, function(err, db_) { if(err) { logger.error(err); } else { db = db_; } }); } app.use(function(req, res, next) { if(!db) { //Database not connected mongo.connect(process.env.MONGO_URL, null, function(err, db_) { if(err) { logger.error(err); res.sendStatus(500); } else { db = db_; next(); } }); } else { next(); } }); // Actual query app.get('/tickets', function(req, res, next) { var collection = db.collection('tickets'); collection.find().toArray(function(err, result) { if(err) { logger.error(err); res.sendStatus(500); return; } res.json(result); }); }); // Standalone server setup var port = process.env.PORT || 3001; http.createServer(app).listen(port, function (err) { if (err) { logger.error(err); } else { logger.info('Listening on http://localhost:' + port); } });
- 只有一件事:我们的微服务的唯一问题是查询完整的门票清单。而已。身份验证,CORS和其他问题将由我们架构中的上层处理。
- 记录:我们使用'winston'库保持记录。现在我们只需登录到控制台,但在以后的版本中,我们会将预定义格式的日志推送到集中位置进行分析。
- 没有依赖:我们的微服务与其他微服务没有依赖关系。
- 轻松扩展:没有依赖关系,单独的流程,只需一个操作,我们的微服务就可以轻松扩展。
- 小巧可读:我们的微服务小巧可读。新开发人员可以立即修改或重写它。
- 数据共享:现在我们的微服务从自己的数据库中读取数据。我们将在以后的帖子中探讨当其他微服务需要更新或创建票证时会发生什么。
- 注册和失败:我们的微服务独立存在。在以后的文章中,我们将探讨如何管理服务发现以及在微服务失败的情况下您可以做些什么。
获取https://github.com/sebadoom/auth0/blob/master/microservices/microservice-1-webtask/server.js。
旁白:对微服务感兴趣?你会喜欢webtasks!
微服务是Auth0堆栈的重要组成部分,我们提出了一种使它更容易使用的好方法。查看webtask.io。
- 轻量且简单的开发工作流程。
- 简化部署。
- 强大的安全模型,方便HTML5和移动应用程序。
- 适用于HTML和数据API的Web友好编程模型。
我们已将上面的示例转换为webtask,看看它有多简单:
npm install wt-cli -g
# This will send an activation link to your email. One time only.
wt init your.name@email.com
# This will return a new endpoint for your webtask
# Use the endpoint here (we have setup a sample DB for this example)
看代码。 将它与我们之前的版本进行比较,看看我们有多少变化。
结论
微服务是进行分布式计算的新方法。 部署和监控工具的进步缓解了管理许多独立服务所带来的痛苦。 好处很明显:使用正确的工具来解决正确的问题,并让团队使用他们的专有技术来解决每个问题。 困难的部分是处理共享数据。 在处理共享数据和服务间依赖关系时,必须考虑特殊注意事项。 数据建模是任何设计中必不可少的步骤,在基于微服务的架构中更是如此。 我们将在以下文章中详细探讨其他常见模式和实践。