企业在实践使用Docker部署、运行微服务应用的时候,无论是一开始就布局微服务架构,或者从传统的单应用架构进行微服务化迁移。都需要能够处理更复杂的集群中的服务调度、编排、监控等问题。下面主要为大家介绍在服务集群下,如何更安全、高效得使用Docker,以及在架构设计上,需要考虑的方方面面。
这里说的是集群中的负载均衡,如果是纯服务端API的话就是指Gateway API的负载均衡,如果使用了Nginx的话,则是指Nginx的负载均衡。我们目前使用的是阿里云的负载均衡服务(通过前端Nginx)。其中一个主要原因是可以跟DNS域名服务进行绑定。对于刚开始不如创业的企业来说,有可以通过Web界面来设置负载均衡的权重,比较便于部分发布、测试验证,以及健康检查监控等等。从效率和节约开发成本上来说都是个比较适合的选择。
如果自己搭建七层负载均衡如使用Nginx或Haproxy的话,也需要保证负责负载均衡的集群也是高可用的,以及提供便捷的集群监控,蓝绿部署等功能。
对于微服务来说,使用的存储技术主要是根据企业的需要。为了节约成本的话,一般都是选用Mysql,在Mysql的引擎选择的话建议选择InnoDB引擎(5.5版本之前默认MyISAM)。InnoDB在处理并发时更高效,其查询性能的差距也可以通过缓存、搜索等方案进行弥补。InnoDB在处理数据拷贝、备份的免费方案有binlog,mysqldump。不过要做到自动化的备份恢复、可监控的数据中心还是需要DBA或者运维团队。相对花费的成本也较高。如果初创企业,也可以考虑依托一些国内外比较大型的云计算平台提供的PaaS服务。
微服务一般按照业务领域进行边界划分,所以微服务最好是一开始就进行分库设计。是否需要进行分表需要根据每个微服务具体的业务领域的发展以及数据进行具体分析。但建议对于比较核心的领域的模型,比如“订单”提前做好分表字段的设计和预留。
Redis是开源的Key-Value结构的数据库。其基于内存,具有高效缓存的性能,同时也支持持久化。其主要有两种持久化方式。一种是RDB,通过指定时间间隔生成数据集的时间点快照从内存写入磁盘进行持久化,但是会引起一定程度的数据丢失,但性能好。另外一种是AOF,其写入机制,有点类似InnoDB的binlog,AOF的文件的命令都是以Redis协议格式保存。这两种持久化是可以同时存在的,在Redis重启时,AOF文件会被优先用于恢复数据。因为持久化是可选项,所以也可以禁用Redis持久化。
在实际的场景中,建议保留持久化。比如目前比较流行的解决短信验证码的验证,就可使用Redis。在微服务架构体系中,也可以用Redis处理一些KV数据结构的场景。轻量级的数据存储方案,也很适合本身强调轻量级方案的微服务。
在实践中,是对Redis进行了缓存、持久化,按照功能特征进行分库的。
在集成Springboot项目中会使用到spring-boot-starter-data-redis来进行Redis的数据库连接以及基础配置、以及spring-data-redis提供的丰富的数据API*Operations*。
另外,如果是要求高吞吐量的应用,可以考虑用Memcached来专门做简单的KV数据结构的缓存。其比较适合大数据量的读取,支持的数据结构类型也比较单一。
目前在涉及到社交相关的模型数据的存储,图形数据库是一种相交关系型数据库更高效、更灵活的选择。图形数据库也是Nosql的一种。其和KV不同,存储的数据主要是数据节点(node),具有指向性的关系(Relationship)以及节点和关系上的属性(Property)。
因为企业主要是Java作为微服务的开发语言,所以选择使用Neo4j,Neo4j是一种基于Java实现的支持ACID的图形数据库。其提供了丰富的JavaAPI。在性能方面,图形数据库的局部性使遍历的速度非常快,尤其是大规模深度遍历。这个是关系型数据库的多表关联无法企及的。
下图是使用Neo4j的WebUI工具展示的一个官方Getting started数据模型示例。示例中的语句MATCH p=()-[r:DIRECTED]->() RETURN p LIMIT 25是Neo4j提供的查询语言——Cypher。
在项目使用时可以集成SpringData的项目Spring Data Neo4j。以及SpringBootStartersspring-boot-starter-data-neo4j
目前应用的比较广泛的开源的面向文档的数据库主要是Mongodb。Mongo具有高可用、高可伸缩性以及灵活的数据结构存储,尤其是对于Json数据结构的存储。比较适合博客、评论等模型的存储。
在开发的过程中,有时候经常会看到有人写了很长很绕、很难维护的多表查询SQL,或者是各种多表关联的子查询语句。对于某一领域模型,当这种场景多的时候,就该考虑接入一套搜索方案了。不要什么都用SQL去解决,尤其是查询的场景。慢查询语句的问题有时候甚至会拖垮DB,如果DB的监控体系做的不到位,可能问题也很难排查。
Elasticsearch是一个基于Apache Lucene实现的开源的实时分布式搜索和分析引擎。Springboot的项目也提供了集成方式: spring-boot-starter-data-elasticsearch以及spring-data-elasticsearch。
对于搜索集群的搭建,可以使用Docker。具体搭建方法可以参考用Docker搭建Elasticsearch集群,对于Springboot项目的集成可以参考在Springboot微服务中集成搜索服务。而且最新的SpringDataElasticsearch已经支持到了5.x版本的ES,可以解决很多2.x版本的痛点了。
如果是小规模的搜索集群,可以用三台低配置的机器搭建。也可以使用一些商业版的PaaS服务。如何选择还是要根据团队和业务的规模、场景来看。
目前除了ES,使用比较广泛的开源搜索引擎还有Solr,Solr也基于Lucene,且专注在文本搜索。ES专注于对于分布式的支持,并且内置了服务发现组件Zen来维护集群状态,相对Solr(需要借助类似Zookeeper实现分布式)部署也更加轻量级。ES除了分析查询,还可以集成日志收集以及做分析处理。
消息队列如前篇所述,可以作为很好的微服务解耦通信方式。在分布式集群的场景下,对于分布式下的最终一致性也可以提供技术基础保障。并且消息队列也可以用来处理流量削锋。
消息队列的对比在此不再赘述。目前公司使用的是阿里云的ONS。因为使用消息队列还是考虑用在对高可用以及易于管理、监控上的要求,所以选择了安全可靠的消息队列平台。
安全性是做架构需要考虑的基础。互联网的环境复杂,保护好服务的安全,也是对用户的基本承诺。安全技术涉及到的范围比较广,本文选几个常见问题以及常用方式来简单介绍下。
分布式集群本身就是对于服务实例安全的一种保障。一台服务器或者某一个服务实例出现问题的时候,负载均衡可以将请求转发到其他可用的服务实例。但很多企业是自建机房,而且是单机房的,这种布局其实比较危险。因为服务器的备份容灾也得不到完整的保障。最怕的就是数据库也是在同一机房,主备全都在一起。不单是安全性得不到很高的保障,平常的运维花销也会比较大。而且需要注意配置防火墙安全策略。
如果可以,尽量使用一些高可用、高可伸缩的稳定性IaaS平台。
1. 预防网络攻击
目前主要的网络攻击有一下几种:
以上只是列举了几种常见的攻击,想要深入了解的可以多看看REST安全防范表。在网络安全领域,一般很容易被初创企业忽视,如果没有一个运维安全团队,最好使用类似阿里云-云盾之类的产品。省心省成本。
2. 使用安全协议
这个不用多说,无论是对于使用Restful API的微服务通信,还是使用的CDN或者DNS服务。涉及到Http协议的,建议都统一使用Https。无论是什么规模的应用,都改防范流量劫持,否则将会给用户带来很不好的使用体验。
3. 鉴权
关于微服务的鉴权前面API Gateway已经有介绍。除了微服务本身之外,我们使用的一些如Mysql,Redis,Elasticsearch,Eureka等服务,也需要设置好鉴权,尽量通过内网访问。不要对外暴露过多的端口。对于微服务的API Gateway,除了鉴权,最好前端通过Nginx来请求API层。
在基于容器技术的微服务的监控体系面临着更复杂的网络、服务环境,日志采集、监控如何能对微服务减少侵入性、对开发者更透明,一直是很多微服务的DevOps在不断思考和实践的。
1. 微服务日志的采集
微服务的API层的监控,需要从API Gateway到每个微服务的调用路径的跟踪,采集以及分析。使用Rest API的话,为了对所有请求进行采集,可以使用Spring Web的OncePerRequestFilter对所有请求进行拦截,在采集日志的时候,也最好对请求的rt进行记录。
除了记录access,request等信息,还需要对API调用进行请求跟踪。如果单纯记录每个服务以及Gateway的日志,那么当Gateway Log出现异常的时候,就不知道其中间是哪一个微服务的容器出现的问题。如果容器达到一定数量,也不可能排查所有容器以及服务实例的日志。比较简单的解决方式就是对log信息都append一个含有容器信息的一段生成的唯一可标识的Trace信息。
日志采集之后,还需要对其进行分析。如果使用E.L.K的技术体系,就可以灵活运用Elasticsearch的实时分布式特性。Logstash可以进行日志进行收集、分析,并将数据同步到Elasticsearch。Kibana结合Logstash和ElasticSearch,提供良好的便于日志分析的WebUI,增强日志数据的可视化管理。
对于数据量大的日志的采集,为了提升采集性能,需要使用上文提到的消息队列。优化后的架构如下:
2. 基础服务的调用日志采集
对于微服务的Rest API的日志采集、分析可以监控请求信息。为了做到全面的监控。在服务内部,对于中间件、基础设施(包括Redis,Mysql,Elasticsearch等)调用的性能的日志采集和分析也是必要的。
对于中间件服务的日志采集,我们目前可以通过动态代理的方式,对于服务调用的如cache、repository(包括搜索和DB)的基础方法,进行拦截及回调。具体的实现方式可以采用字节码生成框架ASM,方式可以参考之前写的一篇ASM(四) 利用Method 组件动态注入方法逻辑,或者相对API友好的Cglib。
最后,结合架构核心的五要素来回顾下我们在搭建Docker微服务架构使用的技术体系:
对于服务集群的解决方案,其实无论是微服务架构或者SOA架构,都是比较通用的。对于优秀架构设计的追求是永无止境的。在跟很多创业公司的技术朋友们接触下来,大家都是比较偏向于快速搭建以及开发、发布服务。然而一方面也觉得微服务的架构会比较复杂。但是微服务本身就是一种敏捷模式的优秀实践。这些朋友往往会在业务飞速发展的时候面临一个困扰,就是服务拆分,数据库的分库分表、通过消息去解耦像面条一样的同步代码,想要优化性能但是无从下手的尴尬。
Apache Thrift
使用Mesos和Marathon管理Docker集群
基于docker-swarm搭建持续集成集群服务
Kubernetes中文文档
本系列文章主要是对于Docker的微服务实践进行技术方案选型以及介绍。不同的业务、团队可能会适合不通过的架构体系和技术方案。
作为架构师应该结合公司近期、长期的战略规划,进行长远的布局。最起码基础的架构也是需要能支撑3年发展的,期间可以不断引入新的技术并进行服务升级和重构。
也许一个架构师从0开始搭建一整套体系并不需要花费多久时间,最需要其进行的就是不断在团队推行Domain-Driven Design。并且使团队一起遵循Clean Code,进行敏捷开发OvO。
PS:本文所有图均原创图,主要使用工具: Processon,OmniGraffle,VisualParadigm
Thanks for your reading!