消费者协调器和组协调器(十二)

消费者协调器和组协调器

      了解了 Kafka 中消费者的分区分配策略之后是否会有这样的疑问:如果消费者客户端中配置了两个分配策略,那么以哪个为准呢?如果有多个消费者,彼此所配置的分配策略并不完全相同,那么以哪个为准?多个消费者之间的分区分配是需要协同的,那么这个协同的过程又是怎样的呢?这一切都是交由消费者协调器(ConsumerCoordinator)和组协调器(GroupCoordinator)来完成的,它们之间使用一套组协调协议进行交互。

旧版消费者客户端的问题

       消费者协调器和组协调器的概念是针对新版的消费者客户端而言的,Kafka 建立之初并没有它们。旧版的消费者客户端是使用 ZooKeeper 的监听器(Watcher)来实现这些功能的。

      每个消费组(<group>)在 ZooKeeper 中都维护了一个 /consumers/<group>/ids 路径,在此路径下使用临时节点记录隶属于此消费组的消费者的唯一标识(consumerIdString),consumerIdString 由消费者启动时创建。消费者的唯一标识由 consumer.id+主机名+时间戳+UUID 的部分信息构成,其中 consumer.id 是旧版消费者客户端中的配置,相当于新版客户端中的 client.id。比如某个消费者的唯一标识为 consumerId_localhost-1510734527562-64b377f5,那么其中 consumerId 为指定的 consumer.id,localhost 为计算机的主机名,1510734527562 代表时间戳,而 64b377f5 表示 UUID 的部分信息。

参考下图,与 /consumers/<group>/ids 同级的还有两个节点:owners 和 offsets,/consumers/<group>/owner 路径下记录了分区和消费者的对应关系,/consumers/<group>/offsets 路径下记录了此消费组在分区中对应的消费位移。

7-4

       每个 broker、主题和分区在 ZooKeeper 中也都对应一个路径:/brokers/ids/<id> 记录了 host、port 及分配在此 broker 上的主题分区列表;/brokers/topics/<topic> 记录了每个分区的 leader 副本、ISR 集合等信息。/brokers/topics/<topic>/partitions/<partition>/state记录了当前 leader 副本、leader_epoch 等信息。

         每个消费者在启动时都会在 /consumers/<group>/ids 和 /brokers/ids 路径上注册一个监听器。当 /consumers/<group>/ids 路径下的子节点发生变化时,表示消费组中的消费者发生了变化;当 /brokers/ids 路径下的子节点发生变化时,表示 broker 出现了增减。这样通过 ZooKeeper 所提供的 Watcher,每个消费者就可以监听消费组和 Kafka 集群的状态了。

       这种方式下每个消费者对 ZooKeeper 的相关路径分别进行监听,当触发再均衡操作时,一个消费组下的所有消费者会同时进行再均衡操作,而消费者之间并不知道彼此操作的结果,这样可能导致 Kafka 工作在一个不正确的状态。与此同时,这种严重依赖于 ZooKeeper 集群的做法还有两个比较严重的问题。

  1. 羊群效应(Herd Effect):所谓的羊群效应是指ZooKeeper 中一个被监听的节点变化,大量的 Watcher 通知被发送到客户端,导致在通知期间的其他操作延迟,也有可能发生类似死锁的情况。
  2. 脑裂问题(Split Brain):消费者进行再均衡操作时每个消费者都与 ZooKeeper 进行通信以判断消费者或broker变化的情况,由于 ZooKeeper 本身的特性,可能导致在同一时刻各个消费者获取的状态不一致,这样会导致异常问题发生。

再均衡的原理

      新版的消费者客户端对此进行了重新设计,将全部消费组分成多个子集,每个消费组的子集在服务端对应一个 GroupCoordinator 对其进行管理,GroupCoordinator 是 Kafka 服务端中用于管理消费组的组件。而消费者客户端中的 ConsumerCoordinator 组件负责与 GroupCoordinator 进行交互。

         ConsumerCoordinator 与 GroupCoordinator 之间最重要的职责就是负责执行消费者再均衡的操作,包括前面提及的分区分配的工作也是在再均衡期间完成的。就目前而言,一共有如下几种情形会触发再均衡的操作:

  • 有新的消费者加入消费组。
  • 有消费者宕机下线。消费者并不一定需要真正下线,例如遇到长时间的GC、网络延迟导致消费者长时间未向 GroupCoordinator 发送心跳等情况时,GroupCoordinator 会认为消费者已经下线。
  • 有消费者主动退出消费组(发送 LeaveGroupRequest 请求)。比如客户端调用了 unsubscrible() 方法取消对某些主题的订阅。
  • 消费组所对应的 GroupCoorinator 节点发生了变更。
  • 消费组内所订阅的任一主题或者主题的分区数量发生变化。

      下面就以一个简单的例子来讲解一下再均衡操作的具体内容。当有消费者加入消费组时,消费者、消费组及组协调器之间会经历一下几个阶段。

第一阶段(FIND_COORDINATOR)

       消费者需要确定它所属的消费组对应的 GroupCoordinator 所在的 broker,并创建与该 broker 相互通信的网络连接。如果消费者已经保存了与消费组对应的 GroupCoordinator 节点的信息,并且与它之间的网络连接是正常的,那么就可以进入第二阶段。否则,就需要向集群中的某个节点发送 FindCoordinatorRequest 请求来查找对应的 GroupCoordinator,这里的“某个节点”并非是集群中的任意节点,而是负载最小的节点。

       如下图所示,FindCoordinatorRequest 请求体中只有两个域(Field):coordinator_key 和 coordinator_type。coordinator_key 在这里就是消费组的名称,即 groupId,coordinator_type 置为0。这个 FindCoordinatorRequest 请求还会在 Kafka 事务中提及,为了便于说明问题,这里我们暂且忽略它。

       Kafka 在收到 FindCoordinatorRequest 请求之后,会根据 coordinator_key(也就是 groupId)查找对应的 GroupCoordinator 节点,如果找到对应的 GroupCoordinator 则会返回其相对应的 node_id、host 和 port信息。

     具体查找 GroupCoordinator 的方式是先根据消费组 groupId 的哈希值计算 __consumer_offsets 中的分区编号,具体算法如代码清单12-1所示:

代码清单12-1 消费组所对应的分区号的计算方式
Utils.abs(groupId.hashCode) % groupMetadataTopicPartitionCount

      其中 groupId.hashCode 就是使用 Java 中 String 类的 hashCode() 方法获得的,groupMetadataTopicPartitionCount 为主题 __consumer_offsets 的分区个数,这个可以通过 broker 端参数 offsets.topic.num.partitions 来配置,默认值为50。

       找到对应的 __consumer_offsets 中的分区之后,再寻找此分区 leader 副本所在的 broker 节点,该 broker 节点即为这个 groupId 所对应的 GroupCoordinator 节点。消费者 groupId 最终的分区分配方案及组内消费者所提交的消费位移信息都会发送给此分区 leader 副本所在的 broker 节点,让此 broker 节点既扮演 GroupCoordinator 的角色,又扮演保存分区分配方案和组内消费者位移的角色,这样可以省去很多不必要的中间轮转所带来的开销。

第二阶段(JOIN_GROUP)

       在成功找到消费组所对应的 GroupCoordinator 之后就进入加入消费组的阶段,在此阶段的消费者会向 GroupCoordinator 发送 JoinGroupRequest 请求,并处理响应。

7-6

如上图所示,JoinGroupRequest 的结构包含多个域:

  • group_id 就是消费组的 id,通常也表示为 groupId。
  • session_timout 对应消费端参数 session.timeout.ms,默认值为10000,即10秒。GroupCoordinator 超过 session_timeout 指定的时间内没有收到心跳报文则认为此消费者已经下线。
  • rebalance_timeout 对应消费端参数 max.poll.interval.ms,默认值为300000,即5分钟。表示当消费组再平衡的时候,GroupCoordinator 等待各个消费者重新加入的最长等待时间。
  • member_id 表示 GroupCoordinator 分配给消费者的id标识。消费者第一次发送 JoinGroupRequest 请求的时候此字段设置为 null。
  • protocol_type 表示消费组实现的协议,对于消费者而言此字段值为“consumer”。

       JoinGroupRequest 中的 group_protocols 域为数组类型,其中可以囊括多个分区分配策略,这个主要取决于消费者客户端参数 partition.assignment.strategy 的配置。如果配置了多种策略,那么 JoinGroupRequest 中就会包含多个 protocol_name 和 protocol_metadata。其中 protocol_name 对应于 PartitionAssignor 接口中的 name() 方法,我们在讲述消费者分区分配策略的时候提及过相关内容。而 protocol_metadata 和 PartitionAssignor 接口中的 subscription() 方法有直接关系,protocol_metadata 是一个 bytes 类型,其实质上还可以更细粒度地划分为 version、topics 和 user_data,如下图所示。

7-7

       version 占2个字节,目前其值固定为0;topics 对应 PartitionAssignor 接口的 subscription() 方法返回值类型 Subscription 中的 topics,代表一个主题列表;user_data 对应 Subscription 中的 userData,可以为空。

      如果是原有的消费者重新加入消费组,那么在真正发送 JoinGroupRequest 请求之前还要执行一些准备工作:

  1. 如果消费端参数 enable.auto.commit 设置为 true(默认值也为 true),即开启自动提交位移功能,那么在请求加入消费组之前需要向 GroupCoordinator 提交消费位移。这个过程是阻塞执行的,要么成功提交消费位移,要么超时。
  2. 如果消费者添加了自定义的再均衡监听器(ConsumerRebalanceListener),那么此时会调用 onPartitionsRevoked() 方法在重新加入消费组之前实施自定义的规则逻辑,比如清除一些状态,或者提交消费位移等。
  3. 因为是重新加入消费组,之前与 GroupCoordinator 节点之间的心跳检测也就不需要了,所以在成功地重新加入消费组之前需要禁止心跳检测的运作。

        消费者在发送 JoinGroupRequest 请求之后会阻塞等待 Kafka 服务端的响应。服务端在收到 JoinGroupRequest 请求后会交由 GroupCoordinator 来进行处理。GroupCoordinator 首先会对 JoinGroupRequest 请求做合法性校验,比如 group_id 是否为空、当前 broker 节点是否是请求的消费者组所对应的组协调器、rebalance_timeout 的值是否在合理的范围之内。如果消费者是第一次请求加入消费组,那么 JoinGroupRequest 请求中的 member_id 值为 null,即没有它自身的唯一标志,此时组协调器负责为此消费者生成一个 member_id。这个生成的算法很简单,具体如以下伪代码所示。

String memberId = clientId + “-” + UUID.randomUUID().toString();

        其中 clientId 为消费者客户端的 clientId,对应请求头中的 client_id。由此可见消费者的 member_id 由 clientId 和 UUID 用“-”字符拼接而成。

选举消费组的leader

       GroupCoordinator 需要为消费组内的消费者选举出一个消费组的 leader,这个选举的算法也很简单,分两种情况分析。如果消费组内还没有 leader,那么第一个加入消费组的消费者即为消费组的 leader。如果某一时刻 leader 消费者由于某些原因退出了消费组,那么会重新选举一个新的 leader,这个重新选举 leader 的过程又更“随意”了,相关代码如下:

private val members = new mutable.HashMap[String, MemberMetadata]
var leaderId = members.keys.head

        解释一下这2行代码:在 GroupCoordinator 中消费者的信息是以 HashMap 的形式存储的,其中 key 为消费者的 member_id,而 value 是消费者相关的元数据信息。leaderId 表示 leader 消费者的 member_id,它的取值为 HashMap 中的第一个键值对的 key,这种选举的方式基本上和随机无异。总体上来说,消费组的 leader 选举过程是很随意的。

选举分区分配策略

        每个消费者都可以设置自己的分区分配策略,对消费组而言需要从各个消费者呈报上来的各个分配策略中选举一个彼此都“信服”的策略来进行整体上的分区分配。这个分区分配的选举并非由 leader 消费者决定,而是根据消费组内的各个消费者投票来决定的。这里所说的“根据组内的各个消费者投票来决定”不是指 GroupCoordinator 还要再与各个消费者进行进一步交互,而是根据各个消费者呈报的分配策略来实施。最终选举的分配策略基本上可以看作被各个消费者支持的最多的策略,具体的选举过程如下:

  1. 收集各个消费者支持的所有分配策略,组成候选集 candidates。
  2. 每个消费者从候选集 candidates 中找出第一个自身支持的策略,为这个策略投上一票。
  3. 计算候选集中各个策略的选票数,选票数最多的策略即为当前消费组的分配策略。

       如果有消费者并不支持选出的分配策略,那么就会报出异常 IllegalArgumentException:Member does not support protocol。需要注意的是,这里所说的“消费者所支持的分配策略”是指 partition.assignment.strategy 参数配置的策略,如果这个参数值只配置了 RangeAssignor,那么这个消费者客户端只支持 RangeAssignor 分配策略,而不是消费者客户端代码中实现的3种分配策略及可能的自定义分配策略。

        在此之后,Kafka 服务端就要发送 JoinGroupResponse 响应给各个消费者,leader 消费者和其他普通消费者收到的响应内容并不相同,首先我们看一下 JoinGroupResponse 的具体结构,如下图所示。

7-8

       JoinGroupResponse 包含了多个域,其中 generation_id 用来标识当前消费组的年代信息,避免受到过期请求的影响。leader_id 表示消费组 leader 消费者的 member_id。

       Kafka 发送给普通消费者的 JoinGroupResponse 中的 members 内容为空,而只有 leader 消费者的 JoinGroupResponse 中的 members 包含有效数据。members 为数组类型,其中包含各个成员信息。member_metadata 为消费者的订阅信息,与 JoinGroupRequest 中的 protocol_metadata 内容相同,不同的是 JoinGroupRequest 可以包含多个 <protocol_name, protocol_metadata> 的键值对,在收到 JoinGroupRequest 之后,GroupCoordinator 已经选举出唯一的分配策略。也就是说,protocol_name 已经确定(group_protocol),那么对应的 protocol_metadata 也就确定了,最终各个消费者收到的 JoinGroupResponse 响应中的 member_metadata 就是这个确定了的 protocol_metadata。由此可见,Kafka 把分区分配的具体分配交还给客户端,自身并不参与具体的分配细节,这样即使以后分区分配的策略发生了变更,也只需要重启消费端的应用即可,而不需要重启服务端。

本阶段的内容可以简要概括为下面2张图。

7-9

7-10

第三阶段(SYNC_GROUP)

      leader 消费者根据在第二阶段中选举出来的分区分配策略来实施具体的分区分配,在此之后需要将分配的方案同步给各个消费者,此时 leader 消费者并不是直接和其余的普通消费者同步分配方案,而是通过 GroupCoordinator 这个“中间人”来负责转发同步分配方案的。在第三阶段,也就是同步阶段,各个消费者会向 GroupCoordinator 发送 SyncGroupRequest 请求来同步分配方案,如下图所示。

7-11

       我们再来看一下 SyncGroupRequest 请求的具体结构,如下图所示。SyncGroupRequest 中的 group_id、generation_id 和 member_id 前面都有涉及,这里不再赘述。只有 leader 消费者发送的 SyncGroupRequest 请求中才包含具体的分区分配方案,这个分配方案保存在 group_assignment 中,而其余消费者发送的 SyncGroupRequest 请求中的 group_assignment 为空。

7-12

      group_assignment 是一个数组类型,其中包含了各个消费者对应的具体分配方案:member_id 表示消费者的唯一标识,而 member_assignment 是与消费者对应的分配方案,它还可以做更具体的划分,member_assignment 的结构如下图所示。

7-13

       与 JoinGroupRequest 请求中的 protocol_metadata 类似,都可以细分为3个更具体的字段,只不过 protocol_metadata 存储的是主题的列表信息,而 member_assignment 存储的是分区信息,member_assignment 中可以包含多个主题的多个分区信息。

      服务端在收到消费者发送的 SyncGroupRequest 请求之后会交由 GroupCoordinator 来负责具体的逻辑处理。GroupCoordinator 同样会先对 SyncGroupRequest 请求做合法性校验,在此之后会将从 leader 消费者发送过来的分配方案提取出来,连同整个消费组的元数据信息一起存入 Kafka 的 __consumer_offsets 主题中,最后发送响应给各个消费者以提供给各个消费者各自所属的分配方案。

       

目录

消费者协调器和组协调器

旧版消费者客户端的问题

再均衡的原理


这里所说的响应就是指 SyncGroupRequest 请求对应的 SyncGroupResponse,SyncGroupResponse 的内容很简单,里面包含的就是消费者对应的所属分配方案,SyncGroupResponse 的结构如下图所示,具体字段的释义可以从前面的内容中推测出来,这里就不赘述了。

7-14

当消费者收到所属的分配方案之后会调用 PartitionAssignor 中的 onAssignment() 方法。随后再调用 ConsumerRebalanceListener 中的 OnPartitionAssigned() 方法。之后开启心跳任务,消费者定期向服务端的 GroupCoordinator 发送 HeartbeatRequest 来确定彼此在线。

消费组元数据信息

我们知道消费者客户端提交的消费位移会保存在 Kafka 的 __consumer_offsets 主题中,这里也一样,只不过保存的是消费组的元数据信息(GroupMetadata)。具体来说,每个消费组的元数据信息都是一条消息,不过这类消息并不依赖于具体版本的消息格式,因为它只定义了消息中的 key 和 value 字段的具体内容,所以消费组元数据信息的保存可以做到与具体的消息格式无关。

7-15

上图中对应的就是消费组元数据信息的具体内容格式,上面是消息的 key,下面是消息的 value。可以看到 key 和 value 中都包含 version 字段,用来标识具体的 key 和 value 的版本信息,不同的版本对应的内容格式可能并不相同,就目前版本而言,key 的 version 为2,而 value 的 version 为1,读者在理解时其实可以忽略这个字段而探究其他具备特定含义的内容。key 中除了 version 就是 group 字段,它表示消费组的名称,和 JoinGroupRequest 或 SyncGroupRequest 请求中的 group_id 是同一个东西。虽然 key 中包含了 version 字段,但确定这条信息所要存储的分区还是根据单独的 group 字段来计算的,这样就可以保证消费组的元数据信息与消费组对应的 GroupCoordinator 处于同一个 broker 节点上,省去了中间轮转的开销。

value 中包含的内容有很多,可以参照和 JoinGroupRequest 或 SyncGroupRequest 请求中的内容来理解,具体各个字段的释义如下。

  • protocol_type:消费组实现的协议,这里的值为“consumer”。
  • generation:标识当前消费组的年代信息,避免收到过期请求的影响。
  • protocol:消费组选取的分区分配策略。
  • leader:消费组的 leader 消费者的名称。
  • members:数组类型,其中包含了消费组的各个消费者成员信息,上图中右边部分就是消费者成员的具体信息,每个具体字段都比较容易辨别,需要着重说明的是 subscription 和 assignment 这两个字段,分别代码消费者的订阅信息和分配信息。

第四阶段(HEARTBEAT)

       进入这个阶段之后,消费组中的所有消费者就会处于正常工作状态。在正式消费之前,消费者还需要确定拉取消息的起始位置。假设之前已经将最后的消费位移提交到了 GroupCoordinator,并且 GroupCoordinator 将其保存到了 Kafka 内部的 __consumer_offsets 主题中,此时消费者可以通过 OffsetFetchRequest 请求获取上次提交的消费位移并从此处继续消费。

      消费者通过向 GroupCoordinator 发送心跳来维持它们与消费组的从属关系,以及它们对分区的所有权关系。只要消费者以正常的时间间隔发送心跳,就被认为是活跃的,说明它还在读取分区中的消息。心跳线程是一个独立的线程,可以在轮询消息的空档发送心跳。如果消费者停止发送心跳的时间足够长,则整个会话就被判定为过期,GroupCoordinator 也会认为这个消费者已经死亡,就会触发一次再均衡行为。

       消费者的心跳间隔时间由参数 heartbeat.interval.ms 指定,默认值为3000,即3秒,这个参数必须比 session.timeout.ms 参数设定的值要小,一般情况下 heartbeat.interval.ms 的配置值不能超过 session.timeout.ms 配置值的1/3。这个参数可以调整得更低,以控制正常重新平衡的预期时间。

       如果一个消费者发生崩溃,并停止读取消息,那么 GroupCoordinator 会等待一小段时间,确认这个消费者死亡之后才会触发再均衡。在这一小段时间内,死掉的消费者并不会读取分区里的消息。这个一小段时间由 session.timeout.ms 参数控制,该参数的配置值必须在broker端参数 group.min.session.timeout.ms(默认值为6000,即6秒)和 group.max.session.timeout.ms(默认值为300000,即5分钟)允许的范围内。

       还有一个参数 max.poll.interval.ms,它用来指定使用消费者组管理时 poll() 方法调用之间的最大延迟,也就是消费者在获取更多消息之前可以空闲的时间量的上限。如果此超时时间期满之前 poll() 没有调用,则消费者被视为失败,并且分组将重新平衡,以便将分区重新分配给别的成员。

     除了被动退出消费组,还可以使用 LeaveGroupRequest 请求主动退出消费组,比如客户端调用了 unsubscrible() 方法取消对某些主题的订阅,这个比较简单,这里就不再赘述了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于简化的微服务架构和Docker容的Microsoft由Microsoft提供的示例.NET Core参考应用程序。   免责声明 重要说明:此示例应用程序的当前状态是ALPHA,认为这是版本0.1版本的基础,因此,很多方面还有待改进和改变显著而重构当前的代码和实现新的功能。对社区的改进和反馈将受到高度的赞赏和接受。 该参考应用程序提出了一个简化的面向服务的体系结构实现,通过综合应用程序引入诸如.NET Core与Docker容之类的技术。然而,这个引用应用程序并不是要解决大型和关键任务的分布式系统中的所有问题,只是让开发人员轻松开始使用.NET Core的Docker容和微服务的开始。 例如,在了解Docker容和使用.NET Core开发微服务之后,下一步(eShopOnContainers还没有涵盖),就是选择像Docker Swarm,Kubernetes或DC / OS(Azure容服务)或Azure中的微服务集群/协调在大多数情况下,服务结构将需要对应用程序的配置进行额外的部分更改(尽管当前体系结构应适用于大多数具有较小更改的业务流程)。或将数据库移动到HA云服务,或者在Azure Service Bus或任何其他生产就绪的服务总线市场上实施EventBus。 在将来,我们可能会分配此项目,并针对特定的微服务集群/协调者加上多个版本,并使用额外的云基础架构。 有关可能的新实施的更多信息,请阅读Wiki中未来版本的eShopOnContainers的计划路线图和里程碑,并在ISSUES部分提供反馈,如果您希望看到任何特定的方案得到实施或改进。此外,请随时讨论任何当前的问题。 架构概述:本参考应用程序是在服务端和客户端的跨平台两种,由于能够根据您的码头工人主机上的Linux或Windows容运行的.NET的核心服务,并为Xamarin的Android,iOS或正在运行的移动应用Windows / UWP加上客户端网络应用程序的任何浏览。该架构提出了一种简化的面向服务的架构实现,其中包含多个自主的微服务(每个拥有自己的数据/ db),并使用Http作为当前的通信协议,在每个微服务(简单的CRUD vs. DDD / CQRS模式)中实现不同的方法。 它还支持异步通信,用于基于集成事件和事件总线以及路线图中定义的其他功能的多个服务的数据更新传播。 微服务的类型不同,这意味着不同的内部架构模式取决于其目的,如下图所示。   最终将添加与其他框架和No-SQL数据库的其他miroservice样式。这是一个很好的机会,来自社区的拉动请求,例如使用Nancy的新微服务,或者甚至其他语言,如Node,Go,Python或具有MongoDB Azure DocDB兼容性的数据容,PostgreSQL,RavenDB,Event Store,MySql等。) 数据库服务/容的重要说明 在该解决方案当前的开发环境配置中,SQL数据库将自动部署样本数据到单个SQL Server for Linux容(SQL数据库的单一共享Docker容),因此整个解决方案可以启动并运行,而无需任何依赖任何云或特定的服务。每个数据库也可以部署为单个Docker容,但是在开发机中,您需要将8GB或更多的内存RAM分配给Docker才能在Docker Linux主机中运行3个SQL Server Docker容, Docker for Windows“或”Docker for Mac“开发环境。 在将Redis缓存作为开发环境的容运行时,定义了类似的情况。 但是,在实际的生产环境中,建议您将数据库(在本例中为SQL Server和Redis)设置为HA(高可用性)服务,如Azure SQL数据库,Redis服务或任何其他集群系统。如果要更改为生产配置,只需在HA云或内部部署服务后更改连接字符串即可。 相关文档和指导 在开发这个参考应用,我们正在创造一个参考指南/电子书名为“构建和开发集装箱和微服务基于.NET应用程序”,其详细阐述了如何开发这种建筑风格(微服务,多克尔容,领域驱动设计某些微服务)以及其他更简单的架构风格,如可以作为Docker容生活的单片应用程序。 还有其他电子书专注于容/ Docker生命周期(DevOps,CI / CD等)与Microsoft Tools,已经发布,另外还有一本关于使用Xamarin.Forms的企业应用程序模式的电子书。您可以下载它们,并在这里开始审查这些指南/电子书:   建筑与发展 集装箱生命周期和CI / CD 应用程序模式与Xamarin.Forms 下载(初稿,在进行的工作) 下载(自2016年后期第一版) 下载(初稿,在进行的工作) 发送反馈给cesardl@microsoft.com 然而,我们鼓励下载和审查“架构与开发电子书”,因为在指导中解释的架构风格和架构模式和技术在解释许多模式实现时使用此参考应用程序,因此您将更好地了解上下文,设计以及在当前架构和内部设计中采取的决策。 应用程序代码概述 在这种回购,你可以找到一个样本参考应用,将帮助您了解如何实现用微服务架构的应用.NET的核心和多克。 示例业务域或场景基于作为多容应用实现的eShop或电子商务。每个容都是使用.NET Core运行的ASP.NET Core开发的一个微服务部署(如basket-microservice,catalog-microservice,ordering-microservice和identity-microservice),因此可以在Linux Containers和Windows Containers 。下面的屏幕截图显示了这些微服务/容和客户端应用程序的VS Solution结构。 (推荐入门时)开放eShopOnContainers-ServicesAndWebApps.sln为仅包含相关的微服务和Web应用程序的服务端项目的解决方案。 开放eShopOnContainers-MobileApps.sln为仅包含所述客户端的移动应用项目的解决方案(仅Xamarin移动应用)。它也是基于mocks独立工作的。 打开eShopOnContainers.sln包含所有项目(所有的客户端应用和服务)的解决方案。 最后,这些微服务由多个客户端网络和移动应用程序消耗,如下所述。 MVC应用程序(ASP.NET核心):它的一个MVC应用程序,你可以找到关于如何消费有趣的场景基于HTTP的从C#在服务端运行的微服务,因为它是一个典型的ASP.NET MVC的核心应用。由于它是一个服务端应用程序,因此内部Docker Host网络内部名称解析可以访问其他容/微服务。 SPA(单页应用):提供了类似的“网上商店的业务功能”,而是开发了角2,打字稿及轻微使用ASP.NET MVC的核心。这是客户端Web应用程序的另一种方法,当您希望拥有更现代的客户端行为时,其行为与每个操作上的典型浏览往返行为不同,但表现为类似于单页应用程序的单页面应用程序桌面应用使用体验。基于HTTP的微服务的消耗由客户端浏览中的TypeScript / JavaScript完成,因此客户端调用微服务来自Docker Host内部网络(从您的网络甚至从互联网)。 Xamarin移动应用(对于iOS,Android和Windows / UWP) :这是一个客户端移动应用程序支持最常见的移动操作系统平台(的iOS,Android和Windows / UWP)。在这种情况下,微服务的消耗是从C#完成的,但是在客户端设备上运行, 为eShopOnContainers设置开发环境 Visual Studio 2017和Windows 这是更直接的入门方式:https://github.com/dotnet/eShopOnContainers/wiki/02.-Setting-eShopOnContainer-solution-up-in-a-Visual-Studio-2017- environment  CLI和Windows 对于喜欢Windows的CLI的用户,使用dotnet CLI,Docker CLI和Windows的VS代码: https://github.com/dotnet/eShopOnContainers/wiki/03.-Setting-the-eShopOnContainers-solution-up-in-a-Windows-CLI-environment-(dotnet-CLI,-Docker-CLI-and-VS-Code) CLI和Mac 对于那些喜欢在Mac上使用CLI的用户,使用dotnet CLI,Docker CLI和VS代码(说明仍然TBD,但类似于Windows CLI):https://github.com/dotnet/eShopOnContainers/wiki/04.-设置eShopOnContainer-in-a-Mac,-VS-Code-and-CLI-environment - (dotnet-CLI,-Docker-CLI-and-VS-Code) 关于测试的Docker容/图像的注意事项 大部分项目的开发和测试的是(如三月初2017)完成对码头工人的Linux容在开发机与“泊坞的Windows”运行,默认是“泊坞的Windows”已安装的Hyper-V的Linux VM(MobiLinuxVM) 。该窗口的容方案,目前正在实施/测试还没有。应用程序应该能够在基于不同Docker基础映像的Windows Nano Containers上运行,因为.NET Core服务也已经在普通Windows(没有Docker)上运行。该应用程序也使用安装了.NET Core和VS代码的开发MacOS机在“Docker for Mac”中进行了部分测试,这仍然是使用在Mac上的VM安装程序上运行的Linux容的“Docker for Windows” 建立。但是,来自社区的Mac环境和Windows Containers的进一步测试和反馈将不胜感激。 发送反馈和建议 如上所述,我们非常感谢您的反馈,改进和想法。您可以在问题部分创建新问题, 或发送电子邮件至eshop_feedback@service.microsoft.com 问题 问题列表:https://github.com/dotnet/eShopOnContainers/issues/107 标签:docker  微服务
《计算机组装与维修》调研报告 一、调研目的 随着科技的进步和信息事业的发展,尤其是计算机技术的发展与网络应用的逐步普及 ,电脑已成为人们工作和生活中不可缺少的东西。IT行业迅猛发展,就业工作岗位也比 比皆是,在最近几年内,IT职场排行榜仍旧处于所有行业中的"老大"。只有对基础知识 的学习才可以受用终身。 关于计算机组装与维修中,掌握主机部件的安装与拆卸的方法,培养良好的观察为、 沟通协作、查找资料能力。 调查目的:了解计算机硬件市场行情;了解商家对大学生市场的需求情况。 调查范围:计算机硬件经营销售人员,大学生消费者。 调查地点:百脑会,校园 调查方式:寻问同学、现场考察、网络查询。 调查结果: 对于 CPU 的调查:CPU 从最初发展至今已经有二十多年的历史了,这期间,按照其处理信息的字长,CPU 可以分为:四位微处理、八位微处理、十六位微处理、三十二位微处理以及六 十四位微处理等等。 二、调研内容 (一)安装选购 根据市场调查,拟出选购一台微机的硬件选配计划。 CPU AMD 3000+ 盒装 内存 金邦512/DRR2 硬盘 ST160G/7200 主板 华硕M2V 显示卡 七彩虹 镭风X1650XT-GD3 UP烈 机箱 金河田ATX+P4300 键盘鼠标 光电套装七彩 光驱 三星DVD 音箱 麦博 M-111 (二)调查显示 如今,Intel 的 CPU 和其兼容产品统治着微型计算机——PC 的大半江山,但是除了 Intel 或AMD 的CPU,还是你可能听说过的其他一些CPU,如HP 的PA-RISC,IBM 的Power4 和 Sun 的UltraSparc 等,只是它们都是精简指令集运算(RISC)处理,使用Unix 的专利操作系统,例如IBM 的AIX 和Sun 的Solaris 等。虽然设计方式和工作原理的过程有区别,但不同处理依然有很多相似之处。从外 表看来,CPU 常常是矩形或正方形的块状物,通过密密麻麻的众多管脚与主板相连,在这块小小的硅 片上,密布着数以百万计的晶体管,它们好像大脑的神经元,相互配合协调,完成着各 种复杂的运算和操作。Intel 发布的第一颗处理4004 仅仅包含2000 个晶体管,而目前最新的Intel Pentium 8400EE 处理包含超过2.3 亿个晶体管,集成度提高了十万倍,这可以说是当今最复杂的集成电路了。随着线宽的 不断降低,以往芯片内部使用的铝连线的导电性能将不敷使用,AMD 在其K7 系列开始采用铜连线技术。而现在这一技术已经得到了广泛应用。随着科技的发展,计 算机硬件价格每一天都在波动,新的产品不断更新换代,生产厂商为了吸引消费群体, 不断推出各种优惠活动;许多大学生对计算机各部件功能及整体功能的认知水平还较低 ,甚至对一些部件根本不了解,这也给个别销售者以可趁之机,利用高价格、低配置欺 骗消费者;一些消费者对自己需要用的配置功能不够了解,而买到不需要的高价格高配 置的产品,在不久产品更新换代时价格大幅下跌而感觉后悔不已;有些消费者因为不够 了解所需商品,而买到比自己需要的配置低的产品,从而给自己的工作生活带来极大地 不便。 CPU 制造工艺的趋势是向密集度愈高的方向发展。密度愈高的IC 电路设计,意味着在同样大小面积的 IC 中,可以拥有密度更高、功能更复杂的电路设计。 (三)主板安装 目前的主板市场仍是Intel 领头,各兼容厂商跟进的局面。放眼未来,随着Intel 820 等新系列主板和AMD K7 主板的出现,主板市场将更有一场好戏。对于带有刚出不久的i7 的笔记本,似乎消费者们并不是很看好。性对于较高的性能,使得热量随之增多,若不 使用散热,对电脑伤害较大,给使用者带来不便。 对于笔记本市场的调查:为了竞争,各品牌之间降价优惠均有出现。由于戴尔电脑选择 厂家直销 , 省去经销商里面的利润成分,所以在性价比方面略占优势。如今性价比相对较高的品牌 :华硕、宏碁、戴尔。 在配置主板、CPU、内存时应注意的问题,配置错误会出现的问题如下: 1. 在配置主板、CPU、内存时应注意他们之间的兼容性,和参数以及运行数率等问题。大多 数计算机机箱的底座上都会有多个固定孔孔位,可使主板确实固定且不会短路,使用铜柱 或者使用塑料卡榫都可以将主板固定到机箱的基座上。最好的方式是使用铜柱来固定主 板,首先小心的寻找主板上的固定孔位,将这些孔对准基座上的固定孔。如果孔能对准 并且有螺丝孔,就表示可以使用铜柱来固定主板。如果孔对准但是只有凹槽,侧表示只 能使用塑料卡榫来固定主板。注意主板固定至定位后,在装上外壳前,请再次检查以确 保所有安装都正确无误。 2. 如果错误会出现开不起机,开机报警,蓝屏,驱动程序用不了等。如果用户使用专门 为INTEL PENTI

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值