曹祖鹏

Results 13 issues of 曹祖鹏

title: CQRS初探 date: 2017-08-26 --- ### CQRS初探 #### 背景 我们惯常开发的概念中,一直以CRUD为主(Create、Retrieve、Update、Delete),默认我们读操作(Retrieve)的对象模型和写操作(Create、Update、Delete)是同一个对象、同一张表,这对简单的业务逻辑来说,比较合适,但是在复杂的业务逻辑下,CRUD就有点力不从心了。 ![AD05C010-B74F-4C8C-AF51-E1BAF16541EE](http://pic.newtech.club/2017-08-29-AD05C010-B74F-4C8C-AF51-E1BAF16541EE.png) #### Command(写)操作 我们对写操作的定义是会改变对象状态的一种操作,状态指的是广义上的,包含了对象所有属性的修改的一种操作,增删改属于写操作。 在我熟悉的电商业务中,写逻辑是比较复杂的,在写之前需要校验很多状态,拿常见的订单创建场景来说,我们需要检查库存的情况,校验用户价格是否正确,校验匹配的优惠活动,校验用户的积分使用情况..... 在退货的场景下面,需要检查双方达成的退款协议,检验货品是否已经处于发货路上,上述任意条件不达成,就不能退货,然后还要有退还积分、优惠劵等一系列的写操作。 从上面的例子可以看出,完成Command主要有三种情况 - 校验,一系列业务逻辑校验 - 变更,变更领域对象中的属性 - 派生,通知相关领域的变更 业务越重,写操作的逻辑复杂性越高,我们的领域驱动设计中的充血模型为什么要强调将数据和操作统一在一个对象中,就是为了解决写操作的复杂逻辑不要散布到其他地方,在领域模型中完成 — 高内聚。 #### Query(读)操作 读操作就是查询数据返回,相比写操作,比较简单一些。我们往往认为相对Command操作,Query没啥业务逻辑,就是把数据展示出来好了,这里并不涉及领域模型的事情。 不过我们的产品经理常常在数据读取显示上给程序员出难题,...

[多研究些架构,少谈些框架(1) -- 论微服务架构的核心概念](https://github.com/JoeCao/JoeCao.github.io/issues/3) [多研究些架构,少谈些框架(2)-- 微服务和充血模型](https://github.com/JoeCao/JoeCao.github.io/issues/4) [多研究些架构,少谈些框架(3)-- 微服务和事件驱动](https://github.com/JoeCao/JoeCao.github.io/issues/5) *2017-6-16 曹祖鹏* 接上篇,我们采用了领域驱动的开发方式,使用了充血模型,享受了他的好处,但是也不得不面对他带来的弊端。这个弊端在分布式的微服务架构下面又被放大。 #### 事务一致性 事务一致性的问题在Monolithic下面不是大问题,在微服务下面却是很致命,我们回顾一下所谓的ACID原则 - Atomicity - 原子性,改变数据状态要么是一起完成,要么一起失败 - Consistency - 一致性,数据的状态是完整一致的 - Isolation - 隔离线,即使有并发事务,互相之间也不影响 - Durability - 持久性, 一旦事务提交,不可撤销...

微服务之构建容错&自动降级的系统 ---------- ### 微服务是什么 MicroService主要是针对以前的Monolithic(单体)服务来说的,类似优步打车(Uber)这样的应用,如果使用Monolithic来架构,可能是这样的 ![graph-01-e1431978090737](https://user-images.githubusercontent.com/3287183/27023280-756b952c-4f84-11e7-8c76-248145788f7e.png) > 注: > STRIPE是支付服务 > SENDGRID是邮件推送服务 > TWILIO是语音、消息的云服务 大部分的项目都是由Monolithic起步的。刚开始最合适不过了,开发简单直接(直接在一个IDE里面就可以调试)、部署方便(搞个war包扔到tomcat里面就能跑)。 但是随着时间的增长,单体应用的缺陷暴露出来了。 - 首先是代码量大大增加 从几千行到几十万行,接手的程序员已经无法搞清楚里面模块交互逻辑和依赖关系了。大家都在小心翼翼的加代码,避免触碰以前的旧代码。至于单元测试,这种怪兽级别的应用,能不能拆分出来单元啊? - 不可避免的超长启动时间 3分钟以内的都算是快的。启动后,程序员抽支烟再回来的不在少数。大量的时间在等待,使得程序员越来越不愿意测试自己的功能,写完了之后直接扔给测试就完事了。测试轮次一次又一次,时间不可避免的浪费。 - 部署扩展困难 各个模块对服务器的性能要求不同,有的占用CPU高,有的需要大量的IO,有的需要更多的内存。部署在一个服务器内相互影响,扩容的话,无法针对性的扩展。 - 单个的bug会损坏整个服务 可能一个模块的内存泄露,会使得整个服务都crash down。 -...

[多研究些架构,少谈些框架(1) -- 论微服务架构的核心概念](https://github.com/JoeCao/JoeCao.github.io/issues/3) [多研究些架构,少谈些框架(2)-- 微服务和充血模型](https://github.com/JoeCao/JoeCao.github.io/issues/4) [多研究些架构,少谈些框架(3)-- 微服务和事件驱动](https://github.com/JoeCao/JoeCao.github.io/issues/5) 多研究些架构,少谈些框架(2)-- 微服务和充血模型 --------- *2017-6-12 曹祖鹏* 上篇我们聊了微服务的DDD之间的关系,很多人还是觉得很虚幻,DDD那么复杂的理论,聚合根、值对象、事件溯源,到底我们该怎么入手呢? 实际上DDD和面向对象设计、设计模式等等理论有千丝万缕的联系,如果不熟悉OOA、OOD,DDD也是使用不好的。不过学习这些OO理论的时候,大家往往感觉到无用武之地,因为大部分的Java程序员开发生涯是从学习J2EE经典的分层理论开始的(Action、Service、Dao),在这种分层理论中,我们基本没有啥机会使用那些所谓的“行为型”的设计模式,这里的核心原因,就是J2EE经典分层的开发方式是“贫血模型”。 Martin Fowler在他的《企业应用架构模式》这本书中提出了两种开发方式“事务脚本”和“领域模型”,这两种开发分别对应了“贫血模型”和“充血模型”。 #### 事务脚本开发模式 - 事务脚本的核心是过程,可以认为大部分的业务处理都是一条条的SQL,事务脚本把单个SQL组织成为一段业务逻辑,在逻辑执行的时候,使用事务来保证逻辑的ACID。最典型的就是存储过程。当然我们在平时J2EE经典分层架构中,经常在Service层使用事务脚本。 ![aa1](https://user-images.githubusercontent.com/3287183/27027640-d534d6ca-4f94-11e7-95bf-1109105caf5b.jpg) 使用这种开发方式,对象只用于在各层之间传输数据用,这里的对象就是“贫血模型”,只有数据字段和Get/Set方法,没有逻辑在对象中。 我们以一个库存扣减的场景来举例: - 业务场景 首先谈一下业务场景,一个下订单扣减库存(锁库存),这个很简单 先判断库存是否足够,然后扣减可销售库存,增加订单占用库存,然后再记录一个库存变动记录日志(作为凭证) - 贫血模型的设计 首先设计一个库存表...

[多研究些架构,少谈些框架(1) -- 论微服务架构的核心概念](https://github.com/JoeCao/JoeCao.github.io/issues/3) [多研究些架构,少谈些框架(2)-- 微服务和充血模型](https://github.com/JoeCao/JoeCao.github.io/issues/4) [多研究些架构,少谈些框架(3)-- 事件驱动架构](https://github.com/JoeCao/JoeCao.github.io/issues/5) [多研究些架构,少谈些框架(4)-- 架构师是技术的使用者而不是信徒](https://github.com/JoeCao/JoeCao.github.io/issues/6) 多研究些架构,少谈些主义(4)-- 架构师是技术的使用者而不是信徒 ------- *2017-6-9 曹祖鹏* ### 架构师是技术的使用者而不是信徒 我承认我是标题党, 为什么要写这篇充满争议的文章?目前架构师这个职位特别火热,程序员的目标都是成为一个令人尊敬的架构师。但是我们真的理解架构师应该做些什么?很多人把架构师和框架师等同起来,认为研究框架多的才是架构师 下面说的情况请勿对号入座。 - **盲目的追新:** 技术人员的喜好往往是什么技术流行就追什么技术。现在的技术发展快,前后端不断涌现各种框架,我们恨不得把这些框架都用在自己的项目里才行,要不然怎么好意思和别人打招呼啊。 我亲身经历,有个技术人员一定要把原来单元测试框架的xml初始数据改为json,他的原话是”json看的更舒服”,但是改完后,我们的单元测试反而难落地了,原因是原来的单元测试框架有个工具是可以将表中的数据自动生成xml的,而改成json后,我们必须手写json数据了。 他的喜好不包括给大家更好用的工具。 - **按技术站队,以结果反推:** 很多人把手段当成了目的,成为了框架的信徒。用了Java开发,你的设计就一定是面向对象的?用了Spring boot就是微服务了吗?这些荒唐的事情却在技术圈不断发生,技术人员甚至会按照语言、框架形成不同的圈子,各种技术圈互相鄙视,互相踩,真相此时无法越辩越明,反而把技术方向带歪了。 ### 技术要和实际场景结合...

title: 比特币UTXO和去中心化系统的设计 date: 2018-01-26 18:00:00 比特币UTXO和去中心化系统的设计 ---- 2018-01-26 曹祖鹏 ## 起因 刚进2018年,区块链突然大火,程序员们可能莫名其妙,不就是一个分布式系统么,怎么突然就要改变互联网了?趁着这个东风,我们了解一些区块链基础知识。看看是否可以改变世界。 ## UTXO是什么 UTXO是Unspent Transaction Output(未消费交易输出)简写。这绝对是比特币的非常特殊的地方,理解UTXO也就理解了比特币去中心化的含义。 说起UTXO必须先要介绍交易模型。以我们平时对交易的理解,我给张三转账了一笔100块钱,那就是我的账上的钱少了100,张三账上的钱多了100。我们再把问题稍微复杂一些,我和张三合起来买一个李四的一个商品390块钱。我的账户支付100,张三账户支付300,李四的帐户获得390,支付宝账户获得了10块钱的转账手续费。那么对这比交易的记录应该是这样的: ![帐户模型](http://os8wjvykw.bkt.clouddn.com/2018-01-26-112822.jpg) 这种记账方式常用在财务记账上。不过作为一个去中心化的系统,是没有一个中心化银行管理你的开户、销户、余额的。没有余额,怎么判断你的账上有100块钱? ![如何确认](http://os8wjvykw.bkt.clouddn.com/2018-01-26-112819.jpg) 此时用户C必须将前面几次交易的比特币输出作为下一个关联交易的输入,具体见下图的no 321笔交易,用户C将前面获得的两次输出,作为输入放在了交易中,然后给自己输出1个比特币的找零(如果不给自己输出找零,那么这个差额就被矿工当成小费了,切记切记)。比特币的程序会判定,如果两个UTXO加在一起不够支付,则交易不成功。 ![区块链基础.001](http://os8wjvykw.bkt.clouddn.com/2018-01-26-112821.jpg) 比特币UTXO使用有点像古代的银锭 - 五两的银锭付给别人二两,需要通过夹剪将一整块银锭剪成两块,二两的给别人,三两的留给自己。对比:比特币在输出中重新创建一个新的UTXO作为给自己的找零 - 要付给别人五两,手上有几块碎银子单都不足五两,则需要将碎银子一起付给对方。对比:比特币在输入中同时引用多个输出UTXO。 这样的做法很繁琐,所以银两在古代并不是一个很普遍的支付方式(别被武侠片给骗了,大部分还是用铜钱)。...

领域驱动设计和Spring(翻译) ----- 原文 http://static.olivergierke.de/lectures/ddd-and-spring/ 1、**介绍** 这篇文章是的介绍一下领域驱动设计的基础构件、概念和Java的web应用(主要是基于Spring框架)之间的关系和区别。 这篇文章的第二部分讲了怎么把实体、聚合根、仓储映射到使用Spring框架的Java应用中 2、领域驱动设计 Eric Evans的《领域驱动设计》无疑是软件设计领域最重要的几本书之一。 这本书主要集中在软件开发中如何处理领域和软件的映射关系— 开始强调领域通用语言(domain ubiquitous language),通过语言来提取模型,最终映射到一个可工作的软件上。 我们已经对软件设计模式比较熟悉了,他是用于描述和提炼Class和Class关系的技术语言。而DDD是一种用于程序员和业务沟通的更通用的语言,使用DDD可以最终将代码映射到模型上。 2.1 基础构件 构件是DDD中的一些专有名词,让我们看一下图 ![DDD的专有名词](https://ws2.sinaimg.cn/large/006tKfTcgy1fh6t3fmnauj31kw154grh.jpg) 2.1.1 限界上下文(Bounded Context) 当进行领域建模的时候,任何将其作为一个整体进行建模的尝试注定会失败。因为各类利益相关者和他们对领域的看法可能完全不同,试图建立一个单一的、独特的模型来满足所有需求是**完全不可能**的,会把系统搞得极为复杂。 让我们看一个示例图,这个图描述了销售领域已经识别出的模型 ![销售领域](https://ws1.sinaimg.cn/large/006tKfTcgy1fh6t73dzmsj31jn105dhn.jpg) 我们把模型元素稍加区分,成为分离的模型,就可以看出客户和订单的,他们是不同上下文的核心的概念。 ![区分](https://ws1.sinaimg.cn/large/006tKfTcgy1fh6t8vsycrj31kw0yjabl.jpg) 在这里,我们确定了系统战略层面的核心部分,这些部分可能都涉及客户或订单的概念,但通常不同限界上下文对它们的属性感兴趣的部分并不相同。比如 Accounting上下文通常对**客户**的计费信息和不同的支付选项感兴趣,而Shipping上下文的对**客户**的唯一目标是运送地址,然后跟踪订单。 Order上下文可能通过**客户**的订单项了解商品信息,但实际上只涉及商品类目基本的内容(译者注:商品规格、商品详情这些信息Order上下文并不关注)。...

title: Java未来也许不再是电商的首选开发语言 date: 2017-12-06 18:00:00 -------- *2017-12-06 曹祖鹏* 好久没更新博客了,很多人催促我更新,最近因为公司的事情一直是忙(其实是懒病发作),特别是被推广了一波后,再不更对不起读者了。 上周我参加了在南京举办的IAS的架构师峰会,和很多同行沟通,特别是和当当网的首席架构师张亮做了一个结对的分享 —《技术架构演变全景图—从单体式到云原生》,分享的形式很特殊,采用了一问一答的方式,我作为提问题的,不断“刁难”张亮,张亮一一解答问题,一番“交锋”后,听众有反馈效果不错,我自己也收获了不少。 最重要的一点体会是Java未来也许不再是一个电商首选语言了。当然在互联网其他领域,Java早就不是首选了,开发繁琐,包体积大、运行时开销大等等,都不适合互联网创业。但是对于互联网电商来说,前面有阿里、京东全线转型Java技术栈的案例,后面像饿了么这样的新兴电商也慢慢的从Python转向Java,示范作用很强。以至于我们这样的电商软件提供商,把整体是Java架构当做卖点之一。 我认为Java的卖点主要是JVM运行时强大、工具链成熟,以Spring为首的庞大的生态提供了完善的开发体验。特别是在满足电商的双十一高并发、大容量场景下,有dubbo、Spring Cloud这样的服务治理框架,不管是Go、Python、Php,都没有类似的框架可以对比,其他开发语言想追上这样的生态环境不是一件简单的事情, 可以说对于目前电商公司来看,Java技术栈是不二的选择。但是正像三体中的降维打击概念,打败你的人不是你同维度的,而是来自其他的领域。Service Mesh(服务网格),这个来自底层云平台基础设施正在向上入侵原有的开发框架的领域。 说起来Service Mesh不是新概念了,在之前就有运维维护nginx的配置,做服务之间的调用代理,但是这个是很原始的状态。目前随着k8s在运维层面一统江山,基于k8s的linkerd、envoy、Istio一系列Service Mesh解决方案发展非常迅速,Willian Morgan(linkerd的CEO)给出Service Mesh定义: *— 服务网格是一个基础设施层,用于处理服务间通讯。云原生应用有着复杂的服务拓扑,服务网格负责在这些拓扑中实现请求的可靠传递。在实践中,服务网格同程实现为一组轻量级的网络代理,它们于应用程序部署在一起,而**对应用程序透明*** 对应用程序透明这几个字要画重点,说明以后再也不需要在**开发层面**关注负载均衡、路由、熔断、限流、服务注册发现、分布式跟踪等等一系列的服务治理内容了,这些都由我们的运行底层设施来完成了。类似网络七层OSI架构定义,我们做上层开发的不需要了解TCP、HTTP具体的协议,而聚焦到我关注的业务逻辑本身,这种情况很快会在微服务领域再次发生。下图预测了在2018年,哪些技术栈可能由于Service Mesh的发展而被抛弃掉。 ![被抛弃的技术栈](http://os8wjvykw.bkt.clouddn.com/2017-12-06-C8FB90CC-4E74-4362-9C72-EB93421D17F4.png) 在这种情况下Java以引为傲的框架都无用武之地了,虽然Java的开发体验依然不错,但是未来的标准不一定是开发者引导的,运维可能会制定所谓的Cloud Native标准,要求满足标准的,才能上平台进行运行和调度。多语言在Service Mesh中一视同仁,我们很可能用Go来开发网络服务,用Php来做Web,用Node来做网关API,用Java做业务逻辑,服务之间的通讯就交给Service Mesh来统一处理,而整个庞大的微服务体系交由k8s这样的平台来调度和编排。...

[多研究些架构,少谈些框架(1) -- 论微服务架构的核心概念](https://github.com/JoeCao/JoeCao.github.io/issues/3) [多研究些架构,少谈些框架(2)-- 微服务和充血模型](https://github.com/JoeCao/JoeCao.github.io/issues/4) [多研究些架构,少谈些框架(3)-- 微服务和事件驱动](https://github.com/JoeCao/JoeCao.github.io/issues/5) 多研究些架构,少谈些框架(1) -- 论微服务架构的核心概念 -------- *2017-6-9 曹祖鹏* #### 微服务架构和SOA区别 微服务现在辣么火,业界流行的对比的却都是所谓的Monolithic单体应用,而大量的系统在十几年前都是已经是分布式系统了,那么微服务作为新的理念和原来的分布式系统,或者说SOA(面向服务架构)是什么区别呢? 我们先看**相同点**: - 需要Registry,实现动态的服务注册发现机制; - 需要考虑分布式下面的事务一致性,CAP原则下,两段式提交不能保证性能,事务补偿机制需要考虑; - 同步调用还是异步消息传递,如何保证消息可靠性?SOA由ESB来集成所有的消息; - 都需要统一的Gateway来汇聚、编排接口,实现统一认证机制,对外提供APP使用的RESTful接口; - 同样的要关注如何再分布式下定位系统问题,如何做日志跟踪,就像我们电信领域做了十几年的信令跟踪的功能; **那么差别在哪?** - 是持续集成、持续部署?对于CI、CD(持续集成、持续部署),这本身和敏捷、DevOps是交织在一起的,我认为这更倾向于软件工程的领域而不是微服务技术本身;...

Python、Go、Java-从一个方法的归属问题引出的思考 ------------------------ ![](https://ws4.sinaimg.cn/large/006tNc79gy1fh9530p7rpj30gm0aujwr.jpg) 今天在讨论原有API系统重构的时候引出来一个问题,Java中有个ItemForm对象,是用于展示商品信息,和界面传递消息交互的。这个Form需要有个方法,要通过对应实体的类变量把Elasticsearch存储它的url地址拼接出来。 ```java public class ItemForm { private String itemId; private String itemName; private String tenantId; public String toEsUrl() { StringBuilder s = new StringBuilder(); s.append("tenant:").append(tenantId).append(",") .append("itemId:").append(itemId); return...