• Jxin
    2020-06-08
    旁外话: 我的能力只能做到描述自己的理解。我描述自己的理解是希望能从栏主和其他学员处获得反馈,从而调整个人认知。我的身边缺少在软件设计上有追求的队友,很感谢有这个平台可以让我试错,交流,调整。 1.我认为软件的结构和核心技术应该是分开的。kafka之所以是消息队列,看的是对消息队列这个模型的实现。kafka之所以是kafka看的是其消息存储这一核心技术的实现。所以,如果我是想通过看kafka了解消息队列,那么就没必要也不该去看存储实现,我该看的是,路由信息管理,消息生产,消息消费这3块核心业务的骨干,以及其旁支功能的选择(限制消息大小,故障节点延后,延迟消费);如果我想知道kafka为什么在mq中间件中如此突出,那么我就得了解其核心技术的实现,也就这里所说的'软硬结合的存储设计'。 2.谈谈对模型的理解。模型是一个抽象的概念,被抽象的对象可以是某个聚合实体(订单中心中的订单),也可以是某个流程或功能(java内存模型中的主存与缓存同步的规则)。分层对模型来说是实现层面的东西,是一种水平方向的拆分,是一个实现上的规范;模型的细粒度拆分(父模型,子模型),应该是一种垂直维度的拆分,子模型的功能要高内聚,其复杂性不该发散到外部。 3.protected long p1, p2, p3, p4, p5, p6, p7; 这个玩意是Disruptor的缓存行填充中的填充字段。Disruptor中的一个元素是一个volatile的long类型,占用8字节。一但一个元素被修改,则与其出于同个缓存行的所有元素的缓存都会失效。这就导致变更索引位1的元素,会导致索引位0的元素缓存也失效(操作时需要重新从主内存加载)。故而Disruptor做了一个缓存行填充的优化,在目标元素的前后都加了7个类型字段,两边都占据掉56个字节。故而保证每个元素都独占缓存行。是一种用空间换时间的优化。 4.04讲说过要拿个开源项目来分析,刚好我拿的也是mq,就借当前这个篇幅补充下。我看的是RocketMq,目前看完了路由信息管理中心,消息生产端和消息存储的逻辑。拿路由信息管理中心NameServer来说。 被抽象的模型对象是路由信息管理中心,既包含路由信息也包含路由信息的管理。路由信息由QueueData,Broker,TopicRouteData三个实体承载,路由信息管理由BrokerLiveInfo和RouteInfoManager负责。 提供了路由注册,路由发现和路由删除三个接口。 路由注册的接口触发是以Nameserver处理Broker的心跳包的方式接入的,具体代码见RouteInfoManager#registerBroker。 路由发现的接口触发Nameserver不管,由客户端定时请求获取路由信息,具体看DefaultRequestProcessor#getRouteInfoByTopic。 路由删除接口的触发是由Nameserver定时10S扫一遍brokerLiveTable。将超时120s的broker信息全部剔除。或者broker正常关闭会来调用。具体见RouteInfoManager#scanNotActiveBroker和unregisterBroker。 评价, 作为路由信息中心,功能相对简单,所以技术设计上就没太多好说的。比较突出的就是NameServer节点间不做信息同步,每个NameServer都单独接收broker的心跳维护路由信息。这样的设计无疑极大降低了NameServer实现的复杂度,毕竟集群内消息同步一直是个头疼的事情。但是这样的方式,在NameServer节点过多和broker节点过多的场景下感觉都会有性能瓶颈(单位时间心跳的次数增多和需要心跳通知的节点增多)。可是这样的设计依旧抗住了大规模集群的场景,用实践案例打了我理论感观的脸。 但作为一个apache开源项目,其代码实现风格实在令人难受。违反单一职责原则,NamesrvController做了外放接口,存储数据,启动定时等等一系列事情。且因为涵盖数据容器的职责,所以还需要再其他类中传递。违反依赖倒置原则,接口都找不到,就不用提啥基于接口而非实现编程了。如果要说这个项目的风格或者说代码设计偏好,那么就是没有原则,甚至都看不到阿里巴巴编程规范的影子。而这个问题不仅是在NameServer一个子模块中,而是在整个rocketMq模块都普遍存在。于此带来的就是,这个项目的新老交接,持续迭代,成本都会比较高。 限于篇幅,其他部分就不表了。rocketMq是个很优秀很成功的产品,但也因为它的光辉,目前其背后的代码实现才越显得格格不入。
    展开

    作者回复: 感谢你的分享,其他人可以从中学习到新的知识。

    共 3 条评论
    53
  • Y024
    2020-11-07
    很多开源项目都会是基于某篇论文实现的,而这篇论文也就成为该项目的灵魂。 对于 Kafka 来说,它的灵魂是: https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying 中文版本:https://www.kancloud.cn/kancloud/log-real-time-datas-unifying/58708

    作者回复: 多谢分享

    
    11
  • escray
    2020-06-08
    看一个项目的实现,主要是去看软件结构和关键技术。 类似于 Kafka 这样的“网红”开源项目,可以找到的结构图和相关资料不少,特别是官方资料还是比较权威的,比平时工作中接触到的那些陈旧代码要好很多。 文中对于 Kafka 的生产者消费者模型的初步提问,并不难以想到,生产者、消费者、集群连接;而后续问出更多的问题——网络抖动、集群……这个就比较需要功力了。 Kafka 的关键技术在于利用了磁盘顺序读写的特性,这个和 Disruptor 利用缓存填充技术颇有异曲同工之妙。而我前两天刚好在“数据结构和算法之美”的打卡活动里面,看过 Disruptor,印象颇深。 顺路去看了“深入浅出计算机组成原理”中关于 Kafka 的章节,还试读了两篇“Kafka 核心技术与实战”,确实应该认真的学习一下 Kafka,这个号称薪资排名比较靠前的技能。 我也好奇,面对 SSD 硬盘,Kafka 怎么办?

    作者回复: 其实也不需要怎么办,享受硬件升级带来的好处就好了,性能自然就提升了。

    共 2 条评论
    7
  • 三生
    2020-06-10
    先后看了php的源代码和laravel,CI,Tp等框架的源码。从从组件到接口,从组件到模型,最后从模型到实现,走完一整个生命周期,学习到了很多优雅的设计,以及扩展如何接入,不过并不真的为什么会这么设计,设计的时候会解决什么样的问题,以及应用场景,当时还是在大学,所以实战经验不是特别丰富,于是自己想动手实现一下框架,看看为什么框架可以引用于不同的架构,逐步扩展,发现思想虽然相同,但是实现的优雅程度还是不可比拟。

    作者回复: 还有一个原因,你没有面对那个问题。所有的代码只是设计的结果,一些东西变复杂通常都是有原因的。

    共 2 条评论
    3
  • Geek_3b1096
    2020-06-09
    现在有工作就不错了,想办法画出一张图,不是最糟

    作者回复: 这个底线太低了吧!

    
    3
  • 业余爱好者
    2020-06-08
    相同的功能可能要不同的软件产品。他们的接口与模型都是差不多的,不同之处就在于实现。所以理解这些产品族以及他们的差异就该从实现入手。 就像LinkedList和ArrayList都可以提供List的功能,但是实现的不同决定了他们各自不同的特性。使用时的选型还是要根据业务场景的需求来的。

    作者回复: 这取决于你的模型是什么,如果是List,LinkedList和ArrayList就是实现。如果是具体类,它们就是各自的模型了。

    
    3
  • 滴流乱转小胖儿
    2020-06-15
    带着问题去学习,确实目的性更强。 问题是想不出那么多问题怎么破? 真是见功力的啊

    作者回复: 想到多少问题是次要的,想问题是主要的。

    
    2
  • monalisali
    2020-06-11
    关于结构图,我觉得可以包含这些内容: 1. 技术上: * 前后端是如何关联起来的 * 系统怎么与存储系统通信的 (DAO?框架) * 大的架构是什么?(MVC) * 有没有最基本的3层架构 2. 业务上 * 各个模块是如何关联的。即:各个模块的Input和Output是什么

    作者回复: 架构图如果包含了这些内容,就成了我说的那种典型的把设计和实现混在一起的图了。

    
    1
  • sam
    2020-06-14
    给老师化繁为简的神奇能力点赞,很多概念让我这前端开发都豁然贯通了

    作者回复: 欢迎邀请更多小伙伴一起学习!

    
    
  • 阳仔
    2020-06-08
    分析软件系统的实现是以模型和接口为基础的。 模型是分层的,每一层都有对外的接口,上层调用下层的接口。 对一层进行展开分析,需要抓住两个关键点软件结构和关键技术。 其实思路就是对软件系统先有一个整体的认识,建立一个大概思维概念,然后再层层深入,剖析具体实现。 同时理解软件实现还要对操作系统有深入的认识,好的软件设计都会考虑软硬件的性能对软件设计的影响,这些操作系统的思想在指导具体开发软件过程中也是非常有意义
    
    6