Browsed by
标签:Design

关于高可用的系统

关于高可用的系统

HighAvailability-BK在《这多年来我一直在钻研的技术》这篇文章中,我讲述了一下,我这么多年来一直在关注的技术领域,其中我多次提到了工业级的软件,我还以为有很多人会问我怎么定义工业级?以及一个高可用性的软件系统应该要怎么干出来?这样我也可以顺理成章的写下这篇文章,但是没有人问,那么,我只好厚颜无耻的自己写下这篇文章了。哈哈。

另外,我在一些讨论高可用系统的地方看到大家只讨论各个公司的技术方案,其实,高可用的系统并不简单的是技术方案,一个高可用的系统其实还包括很多别的东西,所以,我觉得大家对高可用的系统了解的还不全面,为了让大家的认识更全面,所以,我写下这篇文章

理解高可用系统

首先,我们需要理解什么是高可用,英文叫High Availability(Wikipedia词条),基本上来说,就是要让我们的计算环境(包括软硬件)做到full-time的可用性。在设计上一般来说,需要做好如下的设计:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (30 人打了分,平均分: 4.97 )
Loading...
缓存更新的套路

缓存更新的套路

cache看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。

我不知道为什么这么多人用的都是这个逻辑,当我在微博上发了这个贴以后,我发现好些人给了好多非常复杂和诡异的方案,所以,我想写这篇文章说一下几个缓存更新的Design Pattern(让我们多一些套路吧)。

这里,我们先不讨论更新缓存和更新数据这两个事是一个事务的事,或是会有失败的可能,我们先假设更新数据库和更新缓存都可以成功的情况(我们先把成功的代码逻辑先写对)。

更新缓存的的Design Pattern有四种:Cache aside, Read through, Write through, Write behind caching,我们下面一一来看一下这四种Pattern。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (39 人打了分,平均分: 4.90 )
Loading...
分布式系统的事务处理

分布式系统的事务处理

当我们在生产线上用一台服务器来提供数据服务的时候,我会遇到如下的两个问题:

1)一台服务器的性能不足以提供足够的能力服务于所有的网络请求。

2)我们总是害怕我们的这台服务器停机,造成服务不可用或是数据丢失。

于是我们不得不对我们的服务器进行扩展,加入更多的机器来分担性能上的问题,以及来解决单点故障问题。 通常,我们会通过两种手段来扩展我们的数据服务:

1)数据分区:就是把数据分块放在不同的服务器上(如:uid % 16,一致性哈希等)。

2)数据镜像:让所有的服务器都有相同的数据,提供相当的服务。

对于第一种情况,我们无法解决数据丢失的问题,单台服务器出问题时,会有部分数据丢失。所以,数据服务的高可用性只能通过第二种方法来完成——数据的冗余存储(一般工业界认为比较安全的备份数应该是3份,如:Hadoop和Dynamo)。 但是,加入更多的机器,会让我们的数据服务变得很复杂,尤其是跨服务器的事务处理,也就是跨服务器的数据一致性。这个是一个很难的问题。 让我们用最经典的Use Case:“A帐号向B帐号汇钱”来说明一下,熟悉RDBMS事务的都知道从帐号A到帐号B需要6个操作:

  1. 从A帐号中把余额读出来。
  2. 对A帐号做减法操作。
  3. 把结果写回A帐号中。
  4. 从B帐号中把余额读出来。
  5. 对B帐号做加法操作。
  6. 把结果写回B帐号中。

为了数据的一致性,这6件事,要么都成功做完,要么都不成功,而且这个操作的过程中,对A、B帐号的其它访问必需锁死,所谓锁死就是要排除其它的读写操作,不然会有脏数据的问题,这就是事务。那么,我们在加入了更多的机器后,这个事情会变得复杂起来:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (62 人打了分,平均分: 4.79 )
Loading...
类型的本质和函数式实现

类型的本质和函数式实现

(感谢 @文艺复兴记(todd) 投递此文)

在上一篇文章《二叉树迭代器算法》中,我介绍了一种基于栈的二叉树迭代器实现。程序设计语言和Haskell大牛@九瓜 在看过之后评论到:

这里用了 stack 来做,有点偷懒,所以错失了一个抽象思考机会。如果我们能够理解二叉树到线性表的转换过程,完全可以把 Iterator 当作抽象的线性表来看,只要定义了关于 Iterator 的 empty, singleton, 还有 append 操作,实现二叉树的 Iterator 就变得非常直观。

“错失了一个抽象思考机会”是什么意思呢?我理解九瓜的意思是基于栈的实现虽然是正确的,但它缺乏对于迭代器类型本质的理解,不具有通用性。如果能对迭代器进行合适地抽象就可以像二叉树递归遍历一样自然地得出二叉树迭代器,甚至其他更复杂的数据结构,只要我们能写出它的遍历算法,迭代器算法都可以自然推出。

类型的本质

九瓜提到了通过empty, singleton和append操作对Iterator进行抽象,我本来打算直接根据这个思路介绍函数式的二叉树迭代器实现,但是考虑到其实首要的问题在于理解类型的本质,而并不是所有人都具备这个基础,不如先普及一下类型基础再进入具体实现。那么下面我们就先来认识一下类型到底是什么?我们先以来看看表示元素对的Pair类型,可能有人一提到Pair类型马上就会在脑海中浮现出下面的结构:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (18 人打了分,平均分: 4.33 )
Loading...
IoC/DIP其实是一种管理思想

IoC/DIP其实是一种管理思想

关于IoC的的概念提出来已经很多年了,其被用于一种面象对像的设计。我在这里再简单的回顾一下这个概念。我先谈技术,再说管理。

话说,我们有一个开关要控制一个灯的开和关这两个动作,最常见也是最没有技术含量的实现会是这个样子:

然后,有一天,我们发现需要对灯泡扩展一下,于是我们做了个抽象类:

但是,如果有一天,我们发现这个开关可能还要控制别的不单单是灯泡的东西,我们就发现这个开关耦合了灯泡这种类别,非常不利于我们的扩展,于是反转控制出现了。

就像现实世界一样,造开关的工厂根本不关心要控制的东西是什么,它只做一个开关应该做好的事,就是把电接通,把电断开(不管是手动的,还是声控的,还是光控,还是遥控的),而我们的造各种各样的灯泡(不管是日关灯,白炽灯)的工厂也不关心你用什么样的开关,反正我只管把灯的电源接口给做出来,然后,开关厂和电灯厂依赖于一个标准的通电和断电的接口。于是产生了IoC控制反转,如下图:

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (22 人打了分,平均分: 4.59 )
Loading...
从面向对象的设计模式看软件设计

从面向对象的设计模式看软件设计

前些天发了一篇《如此理解面向对象编程》的文章,然后引起了大家的热议。然后我在微博上说了一句——“那23个经典的设计模式和OO半毛钱关系没有,只不过人家用OO来实现罢了……OO的设计模式思想和Unix的设计思想基本没什么差别”,结果引来了一点点争议。所以,我写下这篇文章把我的观点说明一下。我希望这样可以让大家更容易地理解什么是设计模式。我顺便帮OO和 Unix/Linux搞搞基

什么是模式

在正式说明GoF的那23个经典的设计模式其实和OO关系不大并和Unix的设计思想很相似的这个观点之前,让我先来说说什么是模式?设计模式的英文是Design Pattern,模式是Pattern的汉译。所谓Pattern就是一种规则,或是一种模型,或是一种习惯。Pattern这个东西到处都是,并不只有技术圏子里才有。比如:

  • 文章有文章的Pattern。如新闻有新闻的Pattern(第一段话简述了整个新闻),诗歌总是抒情的,论文总是死板的,讲稿总是高谈的,漫画总是幽默的,……
  • 小说有小说的Pattern。比如,
    • 武侠小说必然要整个武林大会,整几个NB的武功和大师,分个正派和反派,还有一个或数个惊天阴谋,坏人总是要在一开始占尽优势,好人总是要力挽狂澜……
    • 言情小说总是要有第三者,总是要有负心人,里面的女子总是要哭得死去活来,但又痴心不改,……
  •  新闻联播的模式是:头10分钟领导很忙,中间10分钟人民很幸福,后10分钟国外很乱。中国政府官方宣传稿也模式也很明显,各种赞美,口号,胜利,总是要坚持个什么,团结个什么,迈向个什么,某某精神,某某思想,群众情绪稳定,不明真相,等等……
  • 春节的模式是,回家,吃饺子,放个鞭炮,给压岁钱,同学聚会…… 同学聚会的模式基本上都是在饭桌上回忆一下校园时光,比较一下各自的当前处境,调戏一下女同学……
  • …… ……

这就是Pattern,只要你细心观察,你会发现这世间有很多很多的Pattern。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (40 人打了分,平均分: 4.60 )
Loading...
用Unix的设计思想来应对多变的需求

用Unix的设计思想来应对多变的需求

之前,@风枫峰 在“这是谁的错?”中说过开发团队对需求来者不拒,而@weidagang 也在“需求变更和IoC”中说过用IoC来最大程度地解决需求变更。今天我也想从Unix设计思想的角度来说说什么是好的软件设计,什么样的设计可以把需求变更对开发的影响降低。(注意:这并不能解决用户或是PM的无理需求,面对无理需求,需要仔细分析需求,而用技术的手段无法搞定这个事,但是可以减轻需求变更带来的痛苦) 我曾经在《Unix传奇》的下篇中写过一些Unix的设计哲学和思想(这里重点推荐大家看一下《The Art of Unix Programming》,我推荐过多次了),以前也发过一篇《一些软件设计的原则》,不过,这些东西都太多了,记不住。其实,这么多年来,我的经验告诉我,无论是Unix设计,还是面向对象设计,还是别的什么如SOA,ECB,消息,事件,MVC,网络七层模型,数据库设计,等等,他们都在干三件事——解耦,解耦,还是解耦所谓解耦,就是让软件的模块和模块间尽量少地依赖起来。

现实当中的例子

让我先举几个现实生活中的例子:

1、现实社会中,制造灯具的工厂完全不关心制造灯泡的工厂,制造灯泡的工厂完全不关心制造灯具的工厂,但是,灯泡和灯饰可以很完美地组合成用户所喜欢的样子(这和@weidagang 在“需求变更和IoC”说到的那个PC的例子相仿)。他们是怎么做到的?

2、互联网上,做网站的人完全不用关心用户在用什么样的操作系统,什么样的客户端浏览器(当然事实上,浏览器的不标准让网站那边很头痛,这里只是举个例),反过来,上网的人也不关心做网站的人在用什么的技术开发网站。但是大家在完全不关心对方的情况下,可以很正常地协同工作在一起。为什么?

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (31 人打了分,平均分: 4.87 )
Loading...
需求变化与IoC

需求变化与IoC

感谢 Todd投递本文 – 微博帐号:@weidagang

需求又变了,怎么办?

先上一个轻松的段子:

程序员XX遭遇车祸成植物人,医生说活下来的希望只有万分之一,唤醒更为渺茫。可他的Lead和亲人没有放弃,他们根据XX工作如命的作风,每天都在他身边念:“XX,需求又改了,该干活了,你快来呀!”,奇迹终于发生了,XX醒来了,第一句话:“需求又改了?”。

这个段子用幽默的方式反映了需求变化是每一个程序员、架构师或项目经理都会经常遇到的问题。面对这个问题,不同的人有不同的应对之道,最近微博上有一段关于需求变化的讨论:

@假装刺猬的猪:我们在软件开发过程中,会持续碰到客户需求变更的情况。如果没有领域建模,我们单纯将问题使用直觉将问题解决,那么等到客户需求变更或者有新的需求时,就会面临一个僵硬的前设计!无法在以前的设计上持续深入的优化模型,导致需求变更无法及时深化。设计实现均滞后与变更!

@高煥堂: <碰到客户需求变更的情况>是合理的;但<领域建模>不是美好的手段!!!

@weidagang: 要不被客户牵着鼻子走,需要自己有很强的设计能力,反过来让客户跟着你的设计来满足你的要求。能做到这点的公司很少,但这是软件行业唯一有希望的出路。

@高煥堂: <这是软件行业唯一有希望的出路>。 Great!!

如何应对需求变化? @假装刺猬的猪 的答案是领域建模,并持续优化模型,适应需求的变化。@高煥堂 则认为领域建模不是美好的手段。我进一步补充,应该“反过来”让自己在需求变化中处于主导地位,而不是被动地适应。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (17 人打了分,平均分: 4.76 )
Loading...
多版本并发控制(MVCC)在分布式系统中的应用

多版本并发控制(MVCC)在分布式系统中的应用

感谢 Todd投递本文 – 微博帐号:weidagang

问题

最近项目中遇到了一个分布式系统的并发控制问题。该问题可以抽象为:某分布式系统由一个数据中心D和若干业务处理中心L1,L2 … Ln组成;D本质上是一个key-value存储,它对外提供基于HTTP协议的CRUD操作接口。L的业务逻辑可以抽象为下面3个步骤:

  1. read: 根据keySet {k1, … kn}从D获取keyValueSet {k1:v1, … kn:vn}
  2. do: 根据keyValueSet进行业务处理,得到需要更新的数据集keyValueSet’ {k1′:v1′, … km’:vm’} (:读取的keySet和更新的keySet’可能不同)
  3. update: 把keyValueSet’更新到D (:D保证在一次调用更新多个key的原子性)

在没有事务支持的情况下,多个L进行并发处理可能会导致数据一致性问题。比如,考虑L1和L2的如下执行顺序:

  1. L1从D读取key:123对应的值100
  2. L2从D读取key:123对应的100
  3. L1将key:123更新为100 + 1
  4. L2将key:123更新为100 + 2

如果L1和L2串行执行,key:123对应的值将为103,但上面并发执行中L1的执行效果完全被L2所覆盖,实际key:123所对应的值变成了102。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (17 人打了分,平均分: 4.24 )
Loading...
Bret Victor – Inventing on Principle

Bret Victor – Inventing on Principle

Bret Victor简历) – 苹果公司的UI交互设计师(大神级的人),在 CUSECCanadian University Software Engineering Conference) 上做了一个题为 “Inventing on Principle” 的演讲(vimeo视频链接),这个演讲中展示了五个示例:

  • 用程序画树。如何把程序绘图变成实时的,如何把程序和图映射起来。
  • 游戏调试。在实时编程的基础上,可以更容易的让你看到程序参数对游戏的调整,甚至对游戏过程的可视化调试。
  • 算法调试。在写二分查找算法时可以实时看到程序的执行过程。边写边看到。
  • 电路图。可以实时地看到电路图中各个部件的对1/0信号的处理。
  • 动画。一种比flash制作动画更NB 的方法。

下面是优酷上的视频——你一定会被示例中的那些编程工具所震撼!

不过,Bret并不是在说什么编程,也不是在说什么技术,他是在说 How to live your life。

阅读全文 Read More

好烂啊有点差凑合看看还不错很精彩 (52 人打了分,平均分: 4.92 )
Loading...