精华内容
下载资源
问答
  • Nacos配置安全最佳实践

    万次阅读 2021-03-23 10:52:46
    并提出配置安全最佳实践。 作者:鲁严波 前言 配置管理作为软件开发中重要的一环,肩负着连接代码和环境的职责,能很好的分离开发人员和维护人员的关注点。 Nacos的配置管理功能就很好地满足了云原生应用...

    简介: 本文讨论了自建Nacos和阿里云MSE的配置安全原理。并提出配置安全最佳实践。

    作者:鲁严波

    前言

     

    配置管理作为软件开发中重要的一环,肩负着连接代码和环境的职责,能很好的分离开发人员和维护人员的关注点。

     

    Nacos的配置管理功能就很好地满足了云原生应用对于配置管理的需求:既能做到配置和代码分离,也能做到配置的动态修改。

     

    在1月份,Nacos出了一个安全漏洞,外部用户能够伪装为Nacos-server来获取/修改配置( https://github.com/alibaba/nacos/issues/4593 )。确认问题后,Nacos火速修复了漏洞,而阿里云的微服务引擎(MSE)也已在1月末将修复方案反向移植到MSE上的Nacos实例上。

     

    在本文中,我们将会从全局视角入手,讨论如何才能保证Nacos配置的安全性(security),即如何保证配置信息不被恶意用户获取或者泄漏。

    Nacos配置架构

     

    Nacos配置部分的整体架构如下:

     

    对于上图中的每一条链路,都需要考虑有没有两个基本的安全动作:认证(Identification)和鉴权(Authentication)

     

    从上图可以看到,配置信息可能的泄漏方式有:

     

    1. 通过Nacos-client获取配置
    2. 通过控制台获取配置
    3. 通过服务器之间的通信协议获取配置
    4. 直接访问持久化层(比如DB)获取配置
    5.  

    可能的泄漏点如下:

     

    认证

    鉴权

    Nacos 客户端

    未登录用户通过客户端获取/修改配置

    用户通过客户端获取/修改了未授权的配置

    配置控制台

    未登录用户通过控制台获取/修改配置

    用户通过控制台获取/修改了未授权的配置

    Nacos集群内

    用户伪装为Nacos集群获取/修改配置

    不需要

    持久化层

    用户直接查DB,获取/修改配置

    不需要

     

    Nacos客户端场景的认证和鉴权

     

    在Nacos客户端尝试从服务端获取配置时,服务端需要确认客户端的身份,并确认该身份有权限获取配置。

     

    开源版本的Nacos

     

    在默认的Nacos server配置中,不会对客户端鉴权,即任何能访问Nacos server的用户,都可以直接获取Nacos中存储的配置。比如一个黑客攻进了企业内网,就能获取所有的业务配置,这样肯定会有安全隐患。

     

    所以需要先开启Nacos server的鉴权。在Nacos server上修改application.properties中的nacos.core.auth.enabled值为true即可:

     

    nacos.core.auth.enabled=true

     

    如上设置后,Nacos客户端获取配置时,需要设置上对应的用户名和密码,才能获取配置:

    String serverAddr = "{serverAddr}";
    Properties properties = new Properties();
    properties.put("serverAddr", serverAddr);
    properties.put("username","nacos-readonly");
    properties.put("password","nacos");
    ConfigService configService = NacosFactory.createConfigService(properties);

     

    上面讲了如何认证用户,即如何确定现在是哪一个用户在访问,但还需要识别用户的权限,当用户访问没有权限获取对应配置的时候,比如库存服务尝试获取支付服务的配置时,就会失败。

     

    我们可以在开源的Nacos控制台上创建用户、设置权限。步骤如下:

     

    首先,访问 localhost:8848/nacos 并登录,在权限控制->用户列表页面,添加用户:

     

    权限控制->角色管理,绑定用户和角色:

     

    给对应角色添加权限,在权限控制->权限管理页面,添加权限:

     

    经过如上配置后,readonly-user就只能访问public命名空间下的配置了。

     

    阿里云MSE-AK/SK

     

    对于小团队,用用户名和密码来做认证鉴权是足够的。但对于中大型团队,密码的定期更换、人员的频繁变动等,都会导致用户名和密码频繁变动。

     

    这时,使用用户名和密码认证鉴权就需要频繁修改并发布应用。为了解决这个问题,Nacos也提供了基于ak/sk的认证方案、ECS关联Ram角色的方案,可以避免用户名和密码修改导致的频繁发布问题。

     

    以阿里云MSE为例,阿里云用户已经普遍使用了阿里云访问控制服务(RAM)作为权限系统,如果MSE和开源一样,使用用户名和密码实现认证和鉴权的话,那么用户就需要在RAM和MSE Nacos两个地方配置权限。这样既不方便用户权限的统一管理、审查,也给用户带来了不一致的体验。

     

    所以MSE(微服务引擎)提供了基于ak/sk的认证方式,操作示例如下:

     

    首先,在MSE上申请一个Nacos实例(并记下实例id),然后在实例详情->参数设置界面,将ConfigAuthEnabled(配置鉴权)参数设置为true,这样匿名用户就无法获取配置:

     

    然后就可以在阿里云RAM系统上配置相关权限。RAM子账号的权限系统可以简单表示如下:

     

    第一步,创建RAM权限策略如下:

     

     

    图中,mse:Get*、mse:List*、mse:Query*表示能读取配置,mse:*表示所有权限,包括修改权限。

     

    acs:mse:*:*:instance/${instanceId}表示授权到实例级别,acs:mse:*:*:instance/${instanceId}/${namespaceId}表示授权到命名空间级别。

     

    第二步,创建用户并赋予权限

     

    填写用户名称:

     

     

    然后获取到用户的ak/sk:

     

     

    给这个用户对应的权限:

     

     

    最后,只需要在代码中添加ak/sk就可以了:

     

    String serverAddr = "{serverAddr}";
    Properties properties = new Properties();
    properties.put("serverAddr", serverAddr);
    properties.put(PropertyKeyConst.ACCESS_KEY, "${accessKey}");
    properties.put(PropertyKeyConst.SECRET_KEY, "${secret}");
    ConfigService configService = NacosFactory.createConfigService(properties);

     

    经过如上配置,客户端在访问MSE上购买的Nacos实例的时候,MSE会校验AK和签名,确认该用户是合法的用户,并校验权限,否则拒绝提供服务。

     

    阿里云MSE-基于ECS的Ram角色认证

     

    当然,在上面的使用方式中,还是要在初始配置(比如srping-cloud-alibaba-nacos-config中的bootstrap.yml文件)中配置AK/SK。黑客入侵内网、或者源码泄漏时,也会存在AK/SK泄漏,导致配置信息泄漏的风险。

     

    在这种情况下,推荐使用ECS关联的RAM角色来做认证。

     

    ECS关联RAM角色对应的授权模型如下:

     

    上述的关键步骤在角色扮演。只有关联了RAM角色的云服务器,才能成功扮演角色,从而获取操作MSE Nacos实例的权限。

     

    如果黑客只获取了代码,也无法成功扮演RAM角色,无法操作MSE Nacos实例。

    如果机器被攻破,那也能在阿里云控制台上取消云服务器关联的角色,及时止损。

    具体的操作步骤如下:

     

    第一步,创建MSE Nacos实例,并创建对应的权限策略(上文有说明,此处不赘述)。

     

    第二步,创建RAM角色并授权

     

    创建RAM角色:

     

     

    创建角色后,为该角色添加对应的权限策略:

     

     

    第三步,将该角色和ECS关联:

     

    在对应的ECS详情页面,点击授予/收回RAM角色:

     

     

    选择对应的角色并授予:

     

    最后一步,在代码中指定RAM角色即可:

     

    String serverAddr = "{serverAddr}";
    Properties properties = new Properties();
    properties.put("serverAddr", serverAddr);
    properties.put(PropertyKeyConst.RAM_ROLE_NAME, "StoreServiceRole");
    ConfigService configService = NacosFactory.createConfigService(properties);

    经过如上配置,Nacos客户端在获取配置时,云服务器会扮演指定的RAM角色,阿里云临时安全令牌(Security Token Service,STS)来访问MSE Nacos实例。

     

    如果攻击者获取代码,也无法在其他机器上运行,因为攻击者的机器没有扮演RAM角色的权限。

     

    如果攻击者获取扮演之后的认证信息,由于STS失效较短(默认是1小时),攻击者拿到后很快就失效,有效减少了攻击面。

     

    如果需要撤销授权,只需要在阿里云控制台上就可以操作,不需要重新发布应用。

     

    相比于AK/SK方式的认证鉴权,ECS关联角色的认证鉴权更可控、更安全,所以推荐使用这种认证鉴权方式。

    配置控制台场景的认证和鉴权

     

    开源版本的Nacos

     

    开源版本的Nacos控制台,在登录的时候,会通过控制台的login接口,获取临时的accessToken,然后后续的操作,都是以accessToken来做认证鉴权。

     

    比如前文提到的readonly-user用户,登录后,就只能看到public命名空间下的配置信息,无法修改、无法查看其他命名空间下的配置信息。

     

    另外,如果需要创建命名空间、删除命名空间,则只能管理员登录才可以。

    开源版本Nacos的认证鉴权,可以参考该文档:https://nacos.io/zh-cn/docs/auth.html

    阿里云MSE

    阿里云MSE由于是对企业提供服务,所以在权限的划分上会更加精细。

     

    资源的分为实例级别(acs:mse:*:*:instance/${instanceId})和命名空间级别(acs:mse:*:*:instance/${instanceId}/${namespaceId})。

     

    对资源的操作也更加精细,比如:

     

    Action

    说明

    CreateEngineNamespace

    创建命名空间

    DeleteEngineNamespace

    删除命名空间

    mse:Get*,mse:List*,mse:Query*

    读取配置(Nacos 客户端和控制台)

    mse:*

    所有权限,包括修改、删除配置

    mse:QueryNacosConfig

    客户端读取配置

    mse:UpdateNacosConfig

    客户端修改配置

     

    比如,只允许读取一个命名空间下的配置,不允许修改。那权限策略就可以写:

     

    {
      "Action": [
        "mse:Get*",
        "mse:List*",
        "mse:Query*"
      ],
      "Resource": [
        "acs:mse:*:*:instance/${instanceId}/${namespaceId}"
      ],
      "Effect": "Allow"
    }

     

    服务器之间的认证

     

    Nacos服务器之间需要同步一些信息,这时也需要认证对方身份,以确认对方真的是Nacos-server,而不是伪装的。

     

    在1.4.1之前,是通过User-Agent这个header来认证的,这种原始的认证方式,很容易被伪造。本文开头提到的,1月份Nacos爆出的漏洞就是这个原因。

     

    所以1.4.1及之后的版本,认证的header以及对应的值可以自己配置。在application.properties中,修改如下值即可:

     

    # 不使用User-Agent来认证
    nacos.core.auth.enable.userAgentAuthWhite=false
    # 认证header的key
    nacos.core.auth.server.identity=Authorization
    # 认证header的value
    nacos.core.auth.server.identity.value=secret

     

    这样,只有发送了header Authorization: secret 的请求,才能确认对方是服务端,才能同步集群信息;否则就拒绝同步。

     

    由于Nacos-server需要全部权限才能同步配置数据,所以对于Nacos-server之间,则不需要做鉴权。

     

    这样,就能让服务器之间的通信也能做到安全可信了。

     

    阿里云MSE上购买的Nacos实例,也已经将上述方案反向移植到了1.2版本上,也不会有对应的安全问题。

     

    持久化层的安全

     

    Nacos的配置信息,都是存储在持久化层的。比如Nacos默认的持久化层是MySQL。

    为了防止通过git或者其他方式将MySQL的用户名和密码泄漏出去,我们需要定时修改MySQL的用户名和密码。

     

    通常的做法是使用两个数据库用户,比如UserA和UserB。如果要更新密码,则按照如下方式操作:

     

    1. 将Nacos server访问数据库的用户从UserA切换到UserB
    2. 更新UserA的密码
    3. 将Nacos server访问数据库的用户从UserB切换回UserA
    4. 更新UserB的密码

     

    作为阿里云产品,MSE都有定时修改数据库用户名密码的策略,所以如果您购买了MSE实例,则不需要担心此问题。

    配置安全最佳实践

     

    捋了一遍Nacos配置安全的关键点,那么怎么才能保证配置安全呢。只需要做到如下最佳实践就可以了:

     

    1. 定期修改密码和ak/sk

     

    在使用Nacos用户名密码(或者ak/sk)认证的情况下(比如使用开源Nacos认证方式),如果恶意用户拿到了Nacos的用户名和密码(或者ak/sk),那么他就有可能拿到应用的配置。但如果定期修改了密码或者ak/sk的话,就能有效限制配置泄漏的时间段,减少攻击面。

     

    1. 使用ECS角色(推荐用法)

     

    当然,在上面的解决方案中,还是会有Nacos用户名密码或者ak/sk在配置中的,而且这些信息的也有可能泄漏,泄漏后的修改也需要重新发布才可以。所以推荐使用阿里云的ecs角色,所有的权限管理都是在阿里云控制台上完成。

     

    1. 轮转Nacos内部认证的key

     

    前文有提到Nacos服务器之间的认证是通过nacos.core.auth.server.identity来完成的,但如果恶意用户入侵,也会导致泄漏,从而导致配置泄漏。

     

    所以对于自建Nacos,需要定期更换nacos.core.auth.server.identity.value,确保恶意用户无法伪装为Nacos server来获取、修改配置。

     

    当然,如果您使用的是MSE托管的Nacos实例的话,MSE会自动轮转,您可以不用担心这一点。

     

    1. 轮转持久化层的用户名和密码

     

    为了防止配置从持久化层泄漏出去,所以需要定时修改持久化层的认证信息。通常Nacos的持久化层都是DB,所以需要定时修改数据库的用户名和密码。

     

    对于MSE用户,则不需要做任何操作,MSE内部会定时修改数据库的用户名和密码

     

    1. 设计安全预案并定时执行

     

    有了如上重重保险,理论上万无一失,但是因为人的操作总有失误,所以还是需要指定安全预案:

     

    • 定时检查配置的监听列表,确认没有未授权的机器在获取配置
    • ak/sk泄漏时,该如何更新ak/sk,如何撤销泄漏的ak/sk
    • 自建Nacos,服务器被攻破后,如何修改nacos.core.auth.server.identity.value的方案

     

    总结

     

    开源的Nacos在配置管理、权限管理上,能基本满足中小企业需求。

     

    而对于中大型企业,阿里云产品MSE支持更加精细、更加灵活的权限配置、安全管理,也能利用和其他阿里云产品一起做到更加安全的配置能力。

     

    当然,不论是自建Nacos还是使用阿里云MSE,都需要关注上述提到的安全点,防止配置信息泄漏,造成业务损失。最后提到的配置安全最佳实践,也能能保证配置泄漏后,有能力及时修复,做到防患未然。

    原文链接

    本文为阿里云原创内容,未经允许不得转载。

    展开全文
  • COLA 4.0:应用架构的最佳实践

    万次阅读 多人点赞 2020-12-09 19:27:54
    前几天和几个饿了么的同学聊天,一听说他们还在使用COLA 1.0,我二话没说,90度...因此,经过仔细反思,有了这一版最新的COLA 4.0,期望回归初心,让COLA真正成为应用架构的最佳实践,帮助广大的业务技术同学,脱离酱缸

    前几天和几个饿了么的同学聊天,一听说他们还在用COLA 1.0,我二话没说,90度鞠躬,赔礼道歉,虚心聆听他们的吐槽。COLA的初衷旨在控制复杂度,救码农于水火,惭愧的是,早期的思想不成熟,设计也多有缺陷,不仅没帮到他们,反而坑了他们,实在抱歉。

    实际上,我在COLA 3.0迭代的时候,已经举起奥卡姆剃刀,砍掉了很多东西。

    然而还不够,主要体现在对架构的思考还不够透彻。再三考量,我觉得有必要对COLA进行一次重新梳理,回归初心,让COLA真正成为应用架构的最佳实践,帮助广大的业务技术同学,脱离酱缸代码的泥潭!

    应用架构的本质

    什么是架构?十个人可能有十个回答,架构在技术的语境下,就和架构师一样魔幻。我曾经看过一本技术书,用了一章的篇幅讨论架构的定义,最终也没有说明白。

    实际上,定义架构也没那么难,如下图所示,架构的本质,简单来说,就是要素结构。所谓的要素(Components)是指架构中的主要元素,结构是指要素之间的相互关系(Relationship)
    image.png

    例如组织架构,其要素是什么?组成组织的要素当然是人,结构呢?结构是人与人之间的关系。因此,组织架构就是关于定义人的职责划分,以及人与人之间协作关系的一种设计方法。

    同样,对于应用架构而言,代码是其核心组成要素,结构就是这些代码该如何被组织,也就是要如何处理模块(Module)、组件(Component)、包(Package)和类(Class)之间的关系。简而言之,应用架构就是要解决代码要如何被组织的问题。
    compo.png

    一个没有架构的应用系统,就像一堆随意堆放、杂乱无章的玩具,只有熵值,没有熵减。而一个有良好架构的应用系统,有章法、有结构,一切都显得紧紧有条。
    image.png

    好的组织架构会遵循一定的架构模式,大部分的组织都会按职能和业务来设计自己的架构。如果你反其道而行之,硬要把销售、财务和技术人员放在一个部门,就会显得很奇怪。

    同样,好的应用架构,也遵循一些共同模式,不管是六边形架构、洋葱圈架构、整洁架构、还是COLA架构,都提倡以业务为核心,解耦外部依赖,分离业务复杂度和技术复杂度

    应用架构的本质,就是要从繁杂的业务系统中提炼出共性,找到解决业务问题的最佳共同模式,为开发人员提供统一的认知,治理混乱。帮助应用系统“从混乱到有序”,COLA架构就是为此而生,其核心职责就是定义良好的应用结构,提供最佳实践

    COLA 架构

    自从COLA诞生以来,已经被使用在很多的业务系统里面,有CRM的业务,有电商的业务,有物流的业务,有外卖业务,有排课系统… COLA作为应用架构,有一定的普适性,是因为业务问题都有一定的共性。例如,典型的业务系统都需要:

    • 接收request,响应response;
    • 做业务逻辑处理,像校验参数,状态流转,业务计算等等;
    • 和外部系统有联动,像数据库,微服务,搜索引擎等;

    正是有这样的共性存在,才会有很多普适的架构思想出现,比如分层架构、六边形架构、洋葱圈架构、整洁架构(Clean Architecture)、DDD架构等等。

    这些应用架构思想虽然很好,但我们很多同学还是“不讲Co德,明白了很多道理,可还是过不好这一生”。问题就在于缺乏实践和指导。COLA的意义就在于,他不仅是思想,还提供了可落地的实践。应该是为数不多的应用架构层面的开源软件。

    分层结构

    假如你是一个公司的CTO要管100号人,你怎么管?按照管理学的定义,一个人的管理幅度如果超过10个,管理就会变得很困难。因此,管100号人,你可以把他们分成10个小组,这样你管理10个小组长就好了。

    所有的复杂系统都会呈现出层级结构,管理如此,软件设计也不例外,你能想象如果网络协议不是四层,而是一层,意味着,你要在应用层去处理链路层的bit数据流会是怎样的情景吗?同样,应用系统处理复杂业务逻辑也应该是分层的,下层对上层屏蔽处理细节,每一层各司其职,分离关注点,而不是一个ServiceImpl解决所有问题

    对于一个典型的业务应用系统来说,COLA会做如下层次定义,每一层都有明确的职责定义:

    image.png

    1)适配层(Adapter Layer):负责对前端展示(web,wireless,wap)的路由和适配,对于传统B/S系统而言,adapter就相当于MVC中的controller;

    2)应用层(Application Layer):主要负责获取输入,组装上下文,参数校验,调用领域层做业务处理,如果需要的话,发送消息通知等。层次是开放的,应用层也可以绕过领域层,直接访问基础实施层;

    3)领域层(Domain Layer):主要是封装了核心业务逻辑,并通过领域服务(Domain Service)和领域对象(Domain Entity)的方法对App层提供业务实体和业务逻辑计算。领域是应用的核心,不依赖任何其他层次;

    4)基础实施层(Infrastructure Layer):主要负责技术细节问题的处理,比如数据库的CRUD、搜索引擎、文件系统、分布式服务的RPC等。此外,领域防腐的重任也落在这里,外部依赖需要通过gateway的转义处理,才能被上面的App层和Domain层使用。

    包结构

    分层是属于大粒度的职责划分,太粗,我们有必要往下再down一层,细化到包结构的粒度,才能更好的指导我们的工作。

    还是拿一堆玩具举例子,分层类似于拿来了一个架子,分包类似于在每一层架子上又放置了多个收纳盒。所谓的内聚,就是把功能类似的玩具放在一个盒子里,这样可以让应用结构清晰,极大的降低系统的认知成本和维护成本
    image.png

    那么,对于一个后端应用来说,应该需要哪些收纳盒呢?这一块的设计真可谓是费了老鼻子劲了,基本上每一次COLA的迭代都会涉及到包结构的调整,迭代到现在,才算基本稳定下来。
    image.png

    各个包结构的简要功能描述,如下表所示:

    层次 包名 功能 必选
    Adapter层 web 处理页面请求的Controller
    Adapter层 wireless 处理无线端的适配
    Adapter层 wap 处理wap端的适配
    App层 executor 处理request,包括command和query
    App层 consumer 处理外部message
    App层 scheduler 处理定时任务
    Domain层 model 领域模型
    Domain层 ability 领域能力,包括DomainService
    Domain层 gateway 领域网关,解耦利器
    Infra层 gatewayimpl 网关实现
    Infra层 mapper ibatis数据库映射
    Infra层 config 配置信息
    Client SDK api 服务对外透出的API
    Client SDK dto 服务对外的DTO

    你可能会有疑问,为什么Domain的model是可选的?因为COLA是应用架构,不是DDD架构。在工作中,很多同学问我领域模型要怎么设计,我的回答通常是:无有必要勿增实体。领域模型对设计能力要求很高,没把握用好,一个错误的抽象还不如不抽象,宁可不要用,也不要滥用,不要为了DDD而DDD。

    问题的关键是要看,新增的模型没有给你带来收益。比如有没有帮助系统解耦,有没有提升业务语义表达能力的提升,有没有提升系统的可维护性和可测性等等。

    模型虽然可选,但DDD的思想是一定要去学习和贯彻的,特别是统一语言、边界上下文、防腐层的思想,值得深入学习,仔细体会。实际上,COLA里面的很多设计思想都来自于DDD。其中就包括领域包的设计

    前面的包定义,都是功能维度的定义。为了兼顾领域维度的内聚性,我们有必要对包结构进行一下微调,即顶层包结构应该是按照领域划分,让领域内聚。

    也就是说,我们要综合考虑功能和领域两个维度包结构定义。按照领域和功能两个维度分包策略,最后呈现出来的,是如下图所示的顶层包节点是领域名称,领域之下,再按功能划分包结构。
    image.png

    例如,在我们刚刚上线的一个云店铺(cloudstore)项目中,按照COLA的分包策略,我们在每一个module下面首先按照领域做一个顶层划分,然后在领域内,再按照功能进行分包。
    image.png

    解耦

    “高内聚,低耦合”这句话,你工作的越久,就越会觉得其有道理。

    所谓耦合就是联系的紧密程度,只要有依赖就会有耦合,不管是进程内的依赖,还是跨进程的RPC依赖,都会产生耦合。依赖不可消除,同样,耦合也不可避免。我们所能做的不是消除耦合,而是把耦合降低到可以接受的程度。在软件设计中,有大量的设计模式,设计原则都是为了解耦这一目的。

    在DDD中有一个很棒的解耦设计思想——防腐层(Anti-Corruption),简单说,就是应用不要直接依赖外域的信息,要把外域的信息转换成自己领域上下文(Context)的实体再去使用,从而实现本域和外部依赖的解耦。

    在COLA中,我们把AC这个概念进行了泛化,将数据库、搜索引擎等数据存储都列为外部依赖的范畴。利用依赖倒置,统一使用gateway来实现业务领域和外部依赖的解耦

    其实现方式如下图所示,主要是在Domain层定义Gateway接口,然后在Infrastructure提供Gateway接口的实现。
    image.png

    举个例子,假如有一个电商系统,对于下单这个操作,它需要联动订单服务、商品服务、库存服务、营销服务等多个系统才能完成。

    那么在订单域,该如何获取商品和库存信息呢?最直接的方式,无外乎就是RPC调用商品和库存服务,拿到DTO直接使用就完了。

    然而,商品域吐出的是一个大而全的DTO(可能包含几十个字段),而在下单这个阶段,订单所需要的可能只是其中几个字段而已。更合适的做法,应该是在订单域中,使用gateway对商品域和库存域的依赖进行解耦。
    image.png

    这样做有两个好处,一个是降低了对外域信息依赖的耦合;另一个是通过上下文映射(Context mapping),确保本领域边界上下文(Bounded context)下领域知识的完整性,实现了统一语言(Ubiquitous language)。

    COLA Archetype

    以上就是COLA架构的核心内容了。然而这么多module,这么多package,如果要手动去创建的话,是非常繁琐和费时的。为了能够快速创建满足COLA架构的应用,我创建了两个Maven Archetype。

    1. 一个是用来创建纯后端服务的archetype:cola-archetype-service。
    2. 一个是用来创建adapter和后端服务一体的web应用archetype:cola-archetype-web。

    另外,你也可以使用阿里云的应用生成器去生成一个COLA应用,只是那边的版本没有同步更新,可能会老旧一点。

    COLA组件

    使用过老版本COLA的同学,应该知道,COLA除了架构之外,还提供了一些框架级别的功能,比如拦截器功能,扩展点功能等。

    之前,这种框架功能和架构混淆在一起,会让人以为使用COLA,就必须要使用这些功能。实际上二者是可以分开使用的,也就是说,你可以单纯的使用COLA架构,而不使用任何COLA组件提供的功能也是完全没问题的

    当然,我还是强烈推荐你可以有选择的使用这些COLA组件,毕竟这些组件都是我们在实际工作中的总结沉淀,其复用性和价值是被反复验证过的。

    为了方便管理,以及更清晰的把架构和框架区分开来。在此次COLA 4.0的升级中,我把这些功能组件全部收拢到了cola-components下面。到目前为止,我们已经沉淀了以下组件:

    组件名称 功能 版本 依赖
    cola-component-dto 定义了DTO格式,包括分页 1.0.0
    cola-component-exception 定义了异常格式,
    主要有BizException和SysException
    1.0.0
    cola-component-statemachine 状态机组件 1.0.0
    cola-component-domain-starter Spring托管的领域实体组件 1.0.0
    cola-component-catchlog-starter 异常处理和日志组件 1.0.0 exception
    ,dto组件
    cola-component-extension-starter 扩展点组件 1.0.0
    cola-component-test-container 测试容器组件 1.0.0

    这些组件是一个良好的开端,我相信,在未来会有更多有用的组件加入。当然,作为一个开源项目,如果你有好的组件idea,欢迎你随时为这个组件库添砖加瓦。

    COLA 4.0

    总结一下,在本次COLA升级中,我们进一步明确了架构和框架功能的定义。升级之后,如下图所示,COLA会被分成COLA架构和COLA组件两个部分:

    1. COLA架构:关注应用架构的定义和构建,提升应用质量。
    2. COLA组件:提供应用开发所需要的可复用组件,提升研发效率。

    image.png

    COLA 开源地址: https://github.com/alibaba/COLA

    你可以按照以下步骤去使用COLA:

    ** 第一步:安装 cola archetype **
    下载cola-archetypes下的源码到本地,然后本地运行mvn install安装。

    ** 第二步:安装 cola components **
    下载cola-components下的源码到本地,然后本地运行mvn install安装。

    ** 第三步:创建应用 **
    执行以下命令:

    mvn archetype:generate  -DgroupId=com.alibaba.demo -DartifactId=demoWeb -Dversion=1.0.0-SNAPSHOT -Dpackage=com.alibaba.demo -DarchetypeArtifactId=cola-framework-archetype-web -DarchetypeGroupId=com.alibaba.cola -DarchetypeVersion=4.0.0
    

    命令执行成功的话,会看到如下的应用代码结构:
    demo

    ** 第四步:运行应用 **
    首先在demoWeb目录下运行mvn install(如果不想运行测试,可以加上-DskipTests参数)。然后进入start目录,执行mvn spring-boot:run。
    运行成功的话,可以看到SpringBoot启动成功的界面。

    生成的应用中,已经实现了一个简单的Rest请求,可以在浏览器中输入 http://localhost:8080/helloworld 进行测试。

    展开全文
  • Cypress 最佳实践

    千次阅读 2019-08-23 14:53:12
    最佳实践:测试spec之间相互独立,用编程的方式登录,控制你的应用的状态 选择元素 错误:使用脆弱的选择器,无法适应改动 最佳实践:使用“data-”属性来为你的选择器提供支持,避免CSS或JS改...

    原文: https://docs.cypress.io/guides/references/best-practices.html

    组织测试,登录,控制状态

    错误:共用页面对象,使用你的UI登录,不截屏
    最佳实践:测试spec之间相互独立,用编程的方式登录,控制你的应用的状态

    选择元素

    错误:使用脆弱的选择器,无法适应改动
    最佳实践:使用“data-”属性来为你的选择器提供支持,避免CSS或JS改动的影响。
    1. 不要基于CSS属性来选择元素如:id, class, tag
    2. 不要基于可能变化的内容比如:元素的文本内容
    3. 添加“data-
    ”属性用于选择元素

    赋值

    错误:试图把命令的返回值赋给变量或者常量,使用const, let或者var
    最佳实践:使用闭包来访问和存储命令返回值
    很多初次使用的用户看到Cypress的代码会认为它是同步运行的,把返回值赋给变量后可以使用,但其实不然。你基本上在Cypress里面用不到const,let和var这样的关键字。如果有,那你大概率是错了。如果你已经熟悉了Cypress但你还是在用const,let和var这说明你可能想要做下面(不应该做,译者注)的事:
    • 你试图存储和比较某些值,比如text, classes, attributes
    • 你试图在不同测试用例与hook之间共享某些值,比如在“before”和“beforeEach”里面。

    访问外部站点

    错误:试图访问可控范围外的站点或服务器
    最佳实践:只测试你能控制的范围。避免访问第三方服务器。如果必须这样做,应该使用“cy.request()”来与第三方服务器通信。

    测试依赖之前的测试

    错误:几个测试耦合在一起
    最佳实践:测试应该可以独立运行而且仍然能够通过。
    有两种方式来解决耦合的问题:
    1. 合并成一个测试
    2. 把共享代码放到“beforeEach”里面

    创建只有一个断言的微型测试

    错误:像写单元测试一样写Cypress测试
    最佳实践:别担心,把多个断言写在一起

    使用“after”和“afterEach”

    错误:使用“after”和“afterEach”这样的hook来清理状态
    最佳实践:在测试运行前清理
    这能保证测试每次都是运行在清理过的环境

    无需等待

    错误:随意使用“cy.wait(Number)”来做延时等待
    最佳实践:使用路由别名或断言来保证Cypress符合某种运行条件
    以下函数都不需要等待:
    • cy.request()
    • cy.visit()
    • cy.get()

    Web服务器

    错误:使用“cy.exec()”或“cy.task()”来起web server
    最佳实践:运行Cypress前启动web server

    设置一个全局baseUrl

    错误:使用“cy.visit()”但没有设baseUrl
    最佳实践:在cypress.json文件中设置baseUrl

    展开全文
  • GraphQL最佳实践

    千次阅读 2018-10-04 07:18:26
    GraphQL最佳实践 下面列出了绑定到网络协议和数据格式,版本控制,授权,缓存和处理长列表(包括分页)领域的一些最佳实践。   JSON(使用 GZIP 压缩)  GraphQL 服务通常返回 JSON 格式的数据,但 GraphQL ...

     

    GraphQL最佳实践

    下面列出了绑定到网络协议和数据格式,版本控制,授权,缓存和处理长列表(包括分页)领域的一些最佳实践。

     

    JSON(使用 GZIP 压缩) 

    GraphQL 服务通常返回 JSON 格式的数据,但 GraphQL 规范 并未要求这一点。对于期望更好的网络性能的 API 层来说,使用 JSON 似乎是一个奇怪的选择,但由于它主要是文本,因而在 GZIP 压缩后表现非常好。

    推荐任何在生产环境下的 GraphQL 服务都启用 GZIP,并推荐在客户端请求头中加入:

    Accept-Encoding: gzip

    客户端和 API 开发人员也非常熟悉 JSON,易于阅读和调试。事实上,GraphQL 语法部分地受到 JSON 语法的启发。

     

    1。协议绑定和数据格式

    GraphQL用于构建分布式系统,因此我们需要讨论如何将数据从客户端发送到服务器并返回。涉及哪些协议以及数据如何序列化?通常,我们将使用GraphQL运行时,它处理协议绑定,序列化和反序列化。请求和响应绑定到HTTP协议,JSON数据格式用于序列化。

    1.1 HTTP请求绑定

    在服务器端,有一个通用HTTP端点(/ graphql),它接收客户端发送给服务器的各种GraphQL请求。发送到GraphQL端点的GraphQL请求由以下组件组成:query / mutation / subscription,以GraphQL查询语言编写。

    变量列表操作名称GraphQL请求可以通过两种方式映射到具有JSON数据结构的HTTP请求:

    (1)以带有查询参数的HTTP GET形式,如1.1.1,或者

    (2)以带有JSON文档的HTTP POST形式,如6.1.1.2节所示。

     

    1.1.1 HTTP GET请求绑定

    如果请求绑定到HTTP GET方法,则查询参数用于编码GraphQL查询,变量和操作名称。该查询只是GraphQL查询语言中的表达式。操作名称是一个简单的字符串。

    变量是一个JSON对象,它包含variablename和variable-value的键值对。此对象根据JSON序列化规则进行序列化。结果如下。

    HTTP GET / graphql?query = {customers {name}}&operationName = op&variables = {“var1”:“val1”,“var2”:“val2”} 6.1.1.2 HTTP POST请求绑定如果请求绑定到HTTP POST,JSON文档用于编码GraphQL查询,变量和操作名称。 请注意,除了查询字段的值之外,所有内容都是根据JSON规则序列化的。 它是一个字符串,该字符串根据GraphQL查询语言的规则进行序列化。 结果如下。

    HTTP POST /graphql

    Content-Type: application/json

    {

    “query”: “{customers{name}}”,

    “operationName”: “op”,

    “variables”: {

    “var1”:“val1”,

    “var2”:“val2”

    }

    }

     

    1.1.2 HTTP响应绑定

    GraphQL响应映射到具有JSON有效负载的HTTP响应,

    响应是返回错误还是实际数据。 返回实际数据时,有效内容是JSON对象,其顶级名称为data。 此对象包含query / mutation / subscription中请求的对象和属性。

    HTTP 200 OK

    Content-Type: application/json

    {

    "data": {

    “customers”:[

    {

    “name”:”Joe”

    },

    {

    “name”:”Bill”

    }

    ]

    }

    }

     

    处理GraphQL请求失败时,将返回错误列表。 每个错误都会详细介绍其他信息,例如包含更多详细信息的消息。

    HTTP 200 OK

    Content-Type: application/json

    {

    ”errors": [

    {

    “message”: ”An error occurred”

    }

    ]

    }

    1.2版本控制成功的软件总是会发生变化.Frederick P. Brooks管理软件系统的变化和发展绝非易事,但是在松散耦合的分布式系统(如API解决方案)中管理变更尤其困难。 API中的一个小变化已足以打破一些使用API的客户端。 从API使用者的角度来看,寿命和稳定性是已发布API的重要方面。 当API发布时,它们可供消费者使用,并且必须假设消费者使用API构建应用程序。 发布的API无法以敏捷方式更改。 至少,API需要保持向后(和向前)兼容,以便旧客户端不会中断,新客户端可以使用新的和改进的功能。

    1.2.1 API更改的类型

    人们可能希望更改已发布API的各个方面。所有这些变化对客户来说同样严重吗?在本节中,我们将分析潜在的变化并根据其严重程度对其进行分类。严重的变化是那些不兼容的变化(参见第6.2.1.2节)并打破了客户。这些API更改并不严重,不会影响客户端。它们被称为向后兼容(参见第6.2.1.1节)。

    1.2.1.1向后兼容的更改

    如果未更改的客户端可以与更改的API交互,则API向后兼容。未更改的客户端应该能够使用旧API提供的所有功能。如果应该向后兼容更改,则禁止对API进行某些更改,而其他更改则是可能的。以下是向后兼容更改的列表:添加字段添加类型添加查询,突变和订阅

    1.2.1.2不兼容的更改

    如果对API的更改破坏了客户端,则更改不兼容。通常,删除和更改API的各个方面会导致不兼容。以下是不兼容更改的非详尽列表:删除现有字段更改现有字段删除类型删除查询,突变或订阅

    1.2.2 GraphQL API中没有版本控制

    由于难以管理演变,理想情况下,API应以这种方式构建,这种演变几乎是不必要的,任何可预见的变化都可以作为兼容的变化来实现。 GraphQL中的版本控制问题并不像构建API的其他哲学那样严重。在GraphQL中,客户端需要在发送请求时决定响应的形状。 GraphQL API仅返回客户端明确请求的字段。

     

    1.3 API的数量

    公司应该有多少个GraphQL API? 只有当所有相关数据都在同一个图表中时,才能充分利用GraphQL的强大功能。 尽可能多的数据应该链接到同一个图表。 然后可以在一个GraphQL API中公开此图。 因此,在同一个GraphQL API中使用完整的API组合是有意义的。

    1.4身份验证和授权

    在API安全性的上下文中使用两个类似的术语 - 身份验证和授权。对于以下讨论,必须了解两者之间的区别。身份验证是回答问题的概念:你是谁?身份验证是一种提供所声明身份证明的方法。

    授权是一个回答问题的概念:你可以做什么?授权提供分配给已确认身份的权限,例如访问权限。身份验证是正确授权的先决条件。

    GraphQL没有规定如何实现身份验证或授权。但是,可以观察到实现身份验证和授权的最佳实践。

    1.4.1身份验证

    最佳做法是在HTTP服务器中处理身份验证,例如在快递。

    HTTP服务器可以使用任何用于认证的标准框架,优选地基于令牌的机制,例如OAuth [6,1]。然后,令牌或用户对象可以在上下文对象中传递给GraphQL解析器函数。

    1.4.2授权

    实施授权的一个好地方是业务逻辑层(参见4.2节),即GraphQL层中的resolve函数和数据库层之间的层。要处理授权,业务层需要有关经过身份验证的用户的信息。它可以通过从服务器传递给业务层的用户对象,通过解析器函数和上下文对象来接收它.

    1.5缓存

    GraphQL与后端的连接可能效率低下。

    这是由于旋转变压器的结构。解析器的结构允许在服务器上编写干净的代码,其中每种类型的每个字段都具有用于解析相应值的专用函数。这种干净概念的简单实现将导致相对低效的实现,并为每个字段提供数据库访问。

    解决方案可以是批处理多个后端请求,并缓存对象的所有字段的响应。 Facebook已出于此目的发布其数据加载器库。它允许构建可以处理缓存的业务层。

    缓存需要标识符。在REST中,使用HTTP缓存,查询路径用于标识对象。有时使用类型特定的标识符,因为它们在数据库表中很容易获得。在GraphQL中,查询路径不是唯一标识符。可以使用各种查询路径访问相同的对象。

    因此,优选使用全局唯一标识符而不是特定类型标识符用于高速缓存。

    1.6长列表和分页

    在GraphQL中处理长列表有几种约定:复数,切片和分页。让我们仔细看看这些选项。

    1.6.1复数

    当在模式中建模1:n关系时,我们使用具有复数形式的名称的字段。这是Plurals得名的地方。多个实现为数组。

    多元实际上不使用任何形式的分页。

    在下面的示例中,我们使用复数来模拟查询类型和书籍类型之间的关系。

    type Query {

    books: [Book]

    }t

    ype Book {

    id: ID!

    title: String

    }

     

    以下查询使用复数来检索所有书籍。

    query {

    books {

    title

    id

    }

    }

     

    1.6.2引入切片(slice)

    切片以限制返回的数据:仅检索前两个/三个/四个等书,或仅检索最后两个/三个/四个等,这是一个数据切片的示例。 这种切片方法可以用于分页,因为我们可以检索前两个,然后是接下来的两个,然后是切片中的下两个。 可以使用偏移(参见第6.6.3节)或使用光标(参见第6.6.4节)实现切片。

    1.6.3使用偏移量

    切片最佳实践是在GraphQL中使用参数优先使用切片。 该参数首先指定页面的大小,即该页面上的项目数。 参数after指定要启动的索引或要启动的元素的id。 在第三本书之后接收两本书对应于以下查询。

    query {

    books(first: 2, after: 3) {

    title

    id

    }

    }

     

    基于第一个和后一个参数的偏移切片不是开箱即用的。它需要在书籍()的解析器功能(参见4.1.2.2和5.3.1节)中实现。

    1.6.4使用光标

    切片使用分页时,我们需要对列表中最后一页结束并开始下一页的点进行建模。这允许我们仅检索已经检索的数据之后存在的数据。到目前为止,我们已经为此目的使用了偏移量。游标是一种比偏移更灵活的概念。如果将新元素添加到列表或从列表中删除,则偏移可能会发生偏差。依赖于偏移量可能会导致我们多次读取相同的元素或跳过一堆元素。如果列表中的更改率高于我们从列表中读取元素的速率,则这尤其糟糕。因此,游标不依赖于列表中的位置,而是依赖于元素的身份。

    游标放在哪里?我们不希望将它们作为业务对象的一部分,因为业务对象可能是多个cursored列表的一部分。这就是我们引入间接的原因。间接是页面的显式表示,其中包含要在页面上显示的业务对象列表和元数据,例如下一页,第一页和最后一页的游标以及是否存在下一页。带有游标的查询可能如下所示。

     

    query {

    books(first: 2, after: Fzmy33==) {

    nodes {

    title

    id

    }

    pageInfo {

    startCursor

    nextCursor

    endCursor

    hasNextPage

    }

    }

    }

     

    页面上的业务对象被建模为一个数组,这里称为节点。

    元数据在pageInfo对象中建模,其中包含字段startCursor,nextCursor,endCursor和hasNextPage。

    展开全文
  • 视频H5 video最佳实践

    万次阅读 2019-05-25 15:51:36
    视频H5 video最佳实践 video的属性 <video id="video" src="video.mp4" controls = "true" poster="images.jpg" // 视频封面 preload="auto" webkit-playsinline="true" /* 这个属性是ios 10中...
  • Git Workflow最佳实践

    千次阅读 2016-09-12 19:26:27
    Git Flow最佳实践
  • Java异常处理最佳实践

    千次阅读 2019-06-30 18:38:55
    在 Java 中处理异常并不是一个简单的事情。不仅仅初学者很难理解,即使一些有经验的开发者也需要花费...本文给出几个被很多团队使用的异常处理最佳实践。 在 finally 块中清理资源或者使用 try-with-resource 语句...
  • Android 最佳实践

    千次阅读 2019-12-25 11:44:33
    Android 最佳实践 此篇文章主要用来记录一些在日常Android开发中比较好用的一些库或者方法 1:TextView相关 通用TextView的封装:https://github.com/lygttpod/SuperTextView 带动画的文字:...
  • TDD最佳实践

    2016-02-16 16:57:01
    这里就先目前阶段,整理一份TDD的最佳实践,在之后的Xunit测试整理中,这份实践会越来越长,对于这份核心在写测试的时候应该时刻注意。 1,在软件开发领域中,从来没有这样的事情:少数的几行代码对大量的代码...
  • SPA 最佳实践

    千次阅读 2014-08-12 15:54:33
    SPA 最佳实践 SPA官方描绘的蛮完美的,但在实践中,还是有很多的坑。下面会一一展示本人在SPA实践项目中遇到的各种坑,以及解决方案。 OPTIMIZER_MODE问题 SQL在目标库实际运行时需要跟源库保持一致,以...
  • AngularJS深度剖析与最佳实践.

    热门讨论 2016-07-07 14:03:48
    AngularJS深度剖析与最佳实践pdf完整版
  • Ansible最佳实践

    千次阅读 2017-01-25 16:57:49
    这篇最佳实践是官网给出的一个Ansible结构的示例,非常的实用,节约代码。看完后,你可能会惊诧于ansible居然这么强大?!翻译中有一些关键字使用的是原文英文,因为不好翻,如有疑问,请戳最上的原文。翻译不当的...
  • Docker 启动 MySQL 最佳实践

    千次阅读 2019-01-27 16:06:40
    Docker 启动 MySQL 最佳实践 本文主要介绍使用 Docker 启动 MySQL 服务的最佳实践,Docker 镜像来自 docker 官方镜像。 启动一个 MySql 5.7 实例 关于版本的选择,修改镜像 tag 即可,支持的 tag 在 docker hub ...
  • Dockerfile 最佳实践

    千次阅读 2016-11-27 19:06:34
    Dockerfile 最佳实践本文是 Docker 官方文档 docs/archive:v1.1 中 Best practices for writing Dockerfiles 的理解和翻译。包含了 Docker 官方对编写 Dockerfile 的最佳做法和建议。这些建议可以让你写出易用高效的...
  • Fragment最佳实践

    千次阅读 2018-02-07 09:53:18
    上一篇文章中详细分析了Fragment相关知识,那么作为“小Activity”,Fragment能做什么呢,如何使用Fragment得到最佳实践呢。Fragment的设计最初也许是为了大屏幕平板设备的需求,不过现在Fragment已经广泛运用到我们...
  • 在线教育流量洪峰最佳实践

    千次阅读 2021-04-01 15:20:57
    直达最佳实践:【在线教育流量洪峰最佳实践最佳实践频道:【最佳实践频道】这里有丰富的企业上云最佳实践,从典型场景入门,提供一系列项目实践方案,降低企业上云门槛的同时满足您的需求!场景描述在线教育等行业...
  • lerna: 最佳实践

    千次阅读 2019-03-11 10:14:45
    该篇文章主要包括在使用lerna的一些注意事项,和使用过程中与其他工具的整合,最终形成的一个最佳实践。 package的指的是一个可以通过npm包管理工具发布的一种目录结构,翻译过来感觉不太适合,所以就用package来...
  • IoT产品的10个最佳实践

    万次阅读 多人点赞 2020-10-26 07:05:27
    如果经历过,有时候就会被人回忆起来。上周末,经过和友人的友人深入地讨论,自己梳理了实现IoT产品的10条经验,并自以为是地称之为“最佳实践”。制造业花了数年甚至数十年时间来磨练他们的产品...
  • Android 6.0 运行时权限管理最佳实践

    万次阅读 多人点赞 2016-09-11 13:11:36
    在Android M中权限系统被重新设计,发生了颠覆性的变化,很多人把握...这里有一切关于Android运行时权限你需要知道的,包括如何在代码中实现,如果你以前不知道这些东西,现在我将在详解之后给你一个最佳实践方案。
  • python docker化最佳实践

    万次阅读 2020-04-15 17:35:23
    相信你也被你第一次使用docker打包的python的image惊讶到了吧,代码1MB...通过最佳实践可以让你的image从v1进化到v2。老司机可以直接到最后去看dockerfile REPOSITORY TAG IMAGE ID CREATED SIZE flask v1 baefe66...
  • JAVA close关闭流最佳实践

    千次阅读 2019-04-27 15:37:31
    JAVA close关闭流最佳实践 文件流用完都要关闭,Java回收机制不会帮你关闭,如果不关闭导致垃圾越来越多,造成资源浪费,接下来谈一下关闭流的最佳实践。 第一种在try块中关闭流,不建议这样使用 import java.awt....
  • OSGi原理与最佳实践(完整版PDF附源代码)

    千次下载 热门讨论 2013-03-14 22:59:42
    OSGi原理与最佳实践(完整版PDF附源代码),改PDF是由纸质书扫描的,内容完整,附带的源代码和书本完全对应。国内OSGI中文第一书,作者是淘宝架构师,书中提及的示例很有代表性,文章也是深入浅出,相当值得拥有!是...
  • actionbar,fragment最佳实践demo

    千次下载 热门讨论 2014-08-21 03:14:38
    Android学习路线(二十四)ActionBar Fragment运用最佳实践demo, 博客地址:http://blog.csdn.net/sweetvvck/article/details/38645297
  • ETL工具Talend最佳实践

    千次阅读 2019-03-01 21:23:45
    文章目录前言最佳实践 前言 和Talend这款软件打交道有一段时间了,主要用它来做一些ETL相关的作业开发,以下总结了一些自己开发配置与过程中的最佳实践最佳实践 可以通过修改Talend Studio 的 .ini 配置文件来给...
  • 接口测试最佳实践

    千次阅读 2016-10-16 17:22:07
    在线阅读学习 接口测试最佳实践
  • 阿里云企业上云最佳实践方案

    千次阅读 2021-03-19 17:05:59
    阿里云解决方案最佳实践,是基于众多客户上云的成功案例萃取而成的最优化企业上云指导。每个最佳实践包括使用场景、多产品部署架构及部署手册。帮助客户更好地理解阿里云的产品和解决方案,降低企业上云门槛的同时...
  • Android最佳实践

    2012-05-24 13:44:16
    Android最佳实践 View more PowerPoint from supernlee
  • RocketMq Consumer 最佳实践

    千次阅读 2018-11-16 16:25:50
    RocketMq Consumer 最佳实践 翻译自RocketMQ官方文档 Consumer Group and Subscriptions 消费集群和订阅 第一件你应该关心的是不同的消费集群能独立的消费相同的topic,每一个都有自己的消费偏移量,需要确保在相同...
  • OpenAPI实现云主机闪电交付最佳实践

    千次阅读 2020-12-25 14:33:11
    直达最佳实践:【OpenAPI实现云主机闪电交付最佳实践最佳实践频道:【点击查看更多上云最佳实践】这里有丰富的企业上云最佳实践,从典型场景入门,提供一系列项目实践方案,降低企业上云门槛的同时满足您的需求!...
  • Docker COPY:Dockerfile最佳实践

    千次阅读 2019-02-27 13:42:20
    本文将解释为什么最佳实践是使用COPY而不是ADD,除非您想要将本地tar文件自动提取到图像中。 使用COPY的最佳做法 为什么你不应该使用ADD 什么时候可以使用ADD 了解更多 使用COPY的最佳做法 此Dockerfile指令将...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 306,358
精华内容 122,543
关键字:

最佳实践