复杂系统设计源自我多年对企业复杂系统的设计的一些思考,类似日记吧,不断完善。
为什么从一个大公司的引入架构师甚至架构师组还是很难架构企业开发中的很多问题?
这些问题表现出架构上的复杂性,和业务上的复杂性。
有时候架构和业务的界限不清晰,非常的模糊。
也可以说是架构设计不合理,也可以说是业务理解不清。
业务实际上是在不断发育的,自己的理解也是在不断深化的,所以这个理解过程是动态的。
复杂源自微观
宏观架构+微观架构
宏观架构:大架构,通用架构
微观架构:小架构。
架构的复杂性首先是多实现,不同实现必然有优劣。
一些解决复杂性问题的手段:微服务化以小博大,服务拆分,流程引擎,规则编排,依赖注入,控制反转,分层方向。
需要不断的抽象业务本质背后的架构,而不是一直写重复的代码。
宏观通用架构手段:
数据:数据库持久,缓存提速,队列缓存。
数据拆分:数据分片
流量拆分:服务器集群
一个假设:服务器一定会挂,所以还要主从或者主备,或者双机
为什么学会很多架构设计理论,一到具体项目就感觉写代码还是很盲目?
例如:软件设计的开闭原则,依赖倒置原则,里氏替换原则,单一职责原则,接口隔离原则
例如单一职责来说,一个看似单一职责的接口实际上由于参数的多变组合实际上是暗含2个职责。
例如依赖倒置原则,注入和new只是形式上的变化,本质上并没有理解注入的益处,当然这种益处是客观存在的,如果面试你去问为什么要IOC,80%的人不知道,潜意识里是大家都这样用,公司要求都这样用。
高内聚,松耦合
业务不断的复杂,并不是微服务简单拆分就可以解决。
微服务的拆分解决了一部分问题,但是依然会引入新问题。
单体的复杂交互如何合理划分领域,领域即使划分了并不是没有耦合,失去耦合本身是一个伪命题。
如果领域划分不好必然是高内聚,强耦合。因为本身上不应该做这种拆分。
设计模式是否可以解决问题?
答案是不能,首先且不说设计模式是否已经包含所有的模式,更主要的是模式是否真正的被理解?
DDD领域驱动是否可以解决问题?
回答是不能,因为没有真正理解业务做出的领域划分只是一个看似完美的划分,实际上用处不大,道理具体的开发的时候发现头重脚轻,处处渗透。
为什么从外面挖个大牛也不是马上就可以让之前设计不好的复杂系统马上设计好?
第一,很难短时间理解所有业务;
第二 之前大牛所在公司的业务并不完全匹配现有业务,可以说完全匹配的业务很少,但是也不是没有。但是也不是非要如此,要时间。
所以,架构师如果并没有真正理解复杂系统设计,而只是被动接收公司的架构,那么他去新公司必然没有太大作用。
简单
能简单就不要复杂。
能不引入中间件就不要引入中间件,比如消息系统,数据量不大没问题,数据量大,业务复杂到一定程度就会出现一些难搞的问题:消息不消费,消息丢失,重复,消费慢,治理能力弱。
CPU和内存的不可控增长,消息不隔离,其实redis缓存也存在这个问题,只看到他的性能和简单没有考虑到失控。
所以有些公司自己自研了MQ来解决这些问题。
一个完整的业务线一定要有一个人懂全部的业务,每一次需求分析,架构设计他一定要参与其中。
并不用去做完整的事情,但是需要对此进行review,特别是领域划分一定要全局业务专家。
千万不要因为政治原因回避这样的人,也不要个人英雄主义,用自己片面的业务理解去做全局的设计。
全局设计必然需要全局业务专家。
对称
世界本身是对称的,明暗,进出...
在计算机也是一样的。
处理无序 需要用有序,本质上就是对称。
序列化:反序列化 编码:解码 进:出 动态代理:反射
不对称就会继续无序下去。
主从复制本质上产生了不对称,最终是对称也就是最终一致性。
那么需要解决这个不对称,除了最终一致性以外就是需要读写对称!也就是读还是写服务器才可以。
配置 与 实际的效果 也是一种对称,无处不在的对称
关于高并发例如秒杀引入队列机制,实际上还是对称的应用。三 -> ||| 时间上的旋转。
同步变异步,更新数据库之后更新缓存引入队列异步 ||| ->三 时间上的旋转。
分布式本质上是对称的时间,集群:服务器之间是对称的。
所以也就出现对称现象,或者对称问题。
高并发的必然也会有高流量,解决的问题是需要不对称,前端系统高流量,到后端需要流量减少。倒三角或者漏洞。
缓存和数据库之间实际上也是对称的,只是一致性是完全对称,否则是不对称。
数据库,远程缓存,本地缓存。
本地缓存性能最好,但是不能超过内存,最大是和内存对称。
分布式完全数据对称是不存在的,因为存在时间,就会有延迟,这是无法消除的。
缓存key 数据库不存在的值 这就是 缓存和数据库不对称,不对称就必然引发不对称问题,解决办法是对称,让这种不存在的值缓存为null。
不过,如果数据库又更新了,那么需要同步双写或者刷新缓存为数据库值,否则引起新的不对称。
不对称也是动态变化的。
分布式MQ下顺序消息实现,下单 生产3个消息 ABC ,要求按照 A-> B ->C顺序消费。
问题 还是 三 -> ||| 镜面折射 到一个点 也就是分区,然后 消费者加锁拿队列锁
后面需要对称的获取 ||| <-三 ,也就是需要锁。
这里发送和接受分别出现对称,产生2面镜子 也就是 同一分区和队列锁。
二维空间 -> 一维空间 <- 二维空间
服务注册:镜像射入
域名负载均衡 ->反射到 注册中心拿到IP 客户端负载均衡 ribbon
反射点从服务端转移到客户端而已
ELK logstash->ES->Kibana
logstash: input->filter->output
镜面射入数据,层层镜面过滤,最后输出
延迟分配:对称 先镜像 再实像
减少内存分配:对称 单例,减小实例尺寸,常量化,静态化(枚举) 对称到一个点
hadoop namenode datanode:对称 映像到不同的实例
未完 。