SUMTEC -- There's a thing in my bloglet.

But it's not only one. It's many. It's the same as other things but it exactly likes nothing else...

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  263 随笔 :: 19 文章 :: 3009 评论 :: 74万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

注:文中提到的案例不是真是实施,只是为了便于描述虚构的;文中提到的公司也非真实发生事件,也只是为了便于描述和理解而使用,并无任何占取利益的意图,请勿对号入座。

通常当我们说要开发一个项目的时候,作为程序设计人员,比较容易想到的地方是,我要有一个比较好的框架,好的代码质量。这是从维护的角度讲的。而稍为正式一点的公司,可能会有一个UE设计部门,专门负责用户体验方面的职责。这是从客户使用的角度讲的。相对来说,这方面的工作已经是比较容易遭受忽略的部分了——试问一下,你所在的企业是否有专人专门负责这一职责?据我的了解,很多公司在这方面是重视程度不足的。当然了,很多公司会有人去做这样的工作,但不一定是专职人员,可能是管产品策划的产品经理,也可能是技术负责人。不过怎么讲,如果说我们需要做这部分工作,大部人人还是较容易得到理解的,毕竟产品好卖与否,市场占有率多大,附加值有多高,跟着客户的感觉是有很大的关联的。

还有一些工作,则非常容易被忽视:部署和维护。


一说到部署和维护,感觉好像就是开发完之后,与程序设计人员无关的一些工作了。比如说部署,那就是找个什么人,往服务器里面一装就好了。再比如说维护,可能就是找个人当客服,把用户的问题收集收集,能解答的解答之,不能解答的找技术人员处理之。看起来似乎真的很简单的事情,其实这里面学问还不少。如果系统在设计的阶段不考虑这部分的内容,那么总有一天就会对你造成很大的压力。这类问题比程序架构问题的潜伏周期更长,暴露出来后,其直观严重性较小。这让我想起来一个典故:“君有疾在腠理,不治将恐深。” 桓侯又不应的原因是因为看起来没什么大问题,如果说哪个手指头动不了了,又或者肚子痛得无法吃饭了,恐怕不会不应的。这些问题的也有点类似,只是更为隐蔽——再怎么积累,看起来也死不了人。因此,我们需要再系统设计的阶段,至少在重构的阶段,就要考虑到这些问题。我要和大家交流的,是原则层次的部分,不涉及到编码,甚至可能不会谈到具体的设计。这些原则都比较简单,应该是比较好应用的。


今天,我只说部署。部署一个相对较大的系统,其实不是一件很简单的工作。先说第一个部署问题:配置文件。

比如说,你会有一堆的配置文件需要配置,会有一堆的周边应用或者服务要随之部署。对于配置文件,恐怕已开始大家都是随便找个地方一搁就好,比如放在APP_DATA目录下,甚至是直接就在web.config里面添加<add key="xxx" value="zzz"/>。这种做法一开始确实觉得很顺手,可是时间一长,你会发现这些配置内容越来越多。多不是问题,问题是他们是有区别的。之所以有配置文件,是因为如果能够通过配置而改变和扩展系统的功能,将会变得很方便。可是这些“改变和扩展”有的是发生在时间轴上,例如随着时间推移发现用户需求改变了。而还有的呢,是发生在空间轴上的,例如部署在不同的机器上需要有不同的配置,比如本地调试的时候可能希望把IP限制全部放开,而真正运营的服务器不能这么干。如果你没有考虑到这一点,很可能会把这些东西都放在一块,最严重的莫过于所有配置都在web.config里面。

“有问题吗?配置文件都是要修改的啊!”没错,甚至一些超大系统的部署工作实际上需要另一个程序去扶助之才能完成。可是如果你的系统没到那么大的程度时,花费人力去做这么一个部署工具实在是不值得。因为这个工具在每一次新版本升级的时候,都需要重新开发测试。对于一些在线运营的系统,很多时候甚至就是小修小补。比如说博客园这样的系统,你总不能说整天“安装”整个新版本吧?这时候部署工具恐怕无能为力,除非你又弄一个“升级/补丁部署工具”来。

“反正这也就是一次性的工作,有那么重要吗?大不了稍微花点时间去弄一下就好了。”也没错,修改一下也不花多少时间——相对开发整个系统来说。可是那也是时间啊!对于一个正在运行的系统,修改配置的速度越快越好,因为它影响你系统的上线速度。而更重要的是,人很容易就会犯错,如果配置方面的设计有问题,就会增加出错的机率。

“容易出错?不会吧?”确实很容易,这个可能需要举一个很具体的例子:

相信不少同学的开发过程是有源代码工具做管理的,那么我们也会发现,这些配置文件通常也受源代码管理工具管理的。这很正常也很有必要,配置文件如何配置,以及其变化,如果丢失了,则很有可能需要花很多时间才能搞清楚如何部署这个系统。比如说这个工具就是TFS,开发的工具是VS。好了,为了便于开发,我们通常也会在开发人员所在的机器中部署一个完整系统,或者子系统、微系统。为了简便,我称为local系统。

“没有!”不会吧?你们的系统大到了这种程度?或者是因为安全方面的原因?好吧,那就没有吧。但是,总会有一个安装在内网的,类似alpha版本的这么一个系统吧?那么,无论是前面说到的local系统,还是这个alpha系统的配置很可能和真实系统之间还是有差别的。比如说,我们的系统可能需要和第三方的某个系统做联动,开发的时候调用的应该是对方提供的一个测试接口——人家肯定不会让你直接一上来就用正式运营的接口的,除非他疯了。相应的,正式版肯定是要调用人家正式的接口。容易想到,这个差异肯定是在配置文件当中的。不容易想到的是,签入到源代码管理工具中的配置,很可能是local或者alpha的配置。那么,当我们部署完正式版——我称之为release版, 我们肯定得要修改这个配置。

到这里,问题还没出现。假设,某天我们发现系统中有一个较大的Bug需要修改,然后呢,需要增加或者修改十几项无论部署在那一台机器都需要的配置。改之,签入。嗯,接下来该打补丁了。我们对比history,发现wwwroot中改了几个aspx/cs文件,有一个dll项目中的cs改了(也就是说这个dll也要重新编译),还有某一个配置文件改了。于是,我们编译好那个dll,连同其他aspx/cs和配置文件一打包,上传到服务器覆盖对应的旧文件,然后重启一下IIS的AppPool(或者保存一下根下面的web.config),好了!真的好了吗?打开IE访问之,真的好了,原来的那几个Bug不见了,新的功能也有了!

过了几天,你可能会惊讶的发现,这几天用户的在线付费都通过测试接口“付钱了”,你也给用户“发货了”。用户付给你的是“测试币”,可你发的可是真货啊!检查后发现,原来上次覆盖的那个配置文件的问题——虽然大部分配置在测试环境和真实环境中没有区别,可是那个接口……

“这个根本就是机制的问题,应该有其他的机制保证!”太对了,不过我是为了便于描述,才省略了中间很多步骤和机制。比如说,你应该有beta/rc等中间过渡测试版本,再比如应该有完整的测试案例,至少是关键测试案例,最后应该有专人检查。但是,没有任何一种机制能够百分之百的打包票的,因此我们通常会设置多个机制来提高可靠性。每增加一个机制,自然就会增加一份成本。而且,如果你打算最后还有人能够检查的话,更是需要这个检查过程能够简单清晰。

“我们这种升级,都不会复制配置文件的!”哎呀,你这么说,我感到太高兴了,因为我也是这么认为的。不过,如果配置文件有修改,是不是变成需要手工干预了?这个过程可能会比较惨痛,而且,通常只有部署的同学才会感同身受,别人通常会站着说话不腰疼——觉得没什么大不了的。

“我们不会都不复制,我们把那些有差别的文件都剔除了。”嘿嘿,这已经比较接近我想要说的方案了。不过还有一个问题:哪些文件是要剔除的?看花眼了吧?

说了半天,也该说出我自认为成功的实践原则了:

1、配置文件的位置要相对集中在一个地方,比如说~/App_Data。与之相反的是到处都有,比如每个目录里面的web.config或者App_Data里面都有点配置,除非真的有必要(通常都是没有必要的);

2、配置文件要按照部署差异归类,比如说~/App_Data/MachineDependent是机器相关的,~/App_Data/MachineIndependent则存放每一台机器都应该相同的配置;

3、暂时没有第三了。

这个很简单的原则,可以让你的部署过程变得更为简单,比如说,部署的时候,只要记得把MachineDependent目录咔嚓掉,通常就不会出什么大乱子了。当然了,这个原则不是银弹,不解决所有的问题,该有rc版还得有,该做检查还得检查,甚至需要手动修改的地方还得手动修改。但是其它因素完全相同的情况下,确实大大简化了一些工作:

1、该复制什么不该复制什么只有一条规则,不容易搞错;

2、不是所有配置都需要手动修改了,有一部分只要复制就好了;

3、即使是要修改的,你也知道在哪里找到他们,而且由于不需要修改的部分已经摘出来了,配置内容肯定相对少了不少,因此看花眼的可能性降低了不少。

即使部署工作全程自动化,哪怕是补丁部署也是自动化的,应用这个原则也会使得开发部署工具会变得更简单清晰一些,最后人工检查也更轻松一点。当然了,这里说的只是原则,实际上要应用这个原则,简单点可以“告知”开发人员即可,复杂点的,我建议把配置相关的东西封装到底层,不允许开发人员直接接触配置文件,这样会更好一些。


还有一种部署问题,是周边的小服务、小应用。请注意,我要说的不是如何部署周边服务,而是说,如何设计才能减少因为部署周边小服务小应用而产生的问题。

不可避免的,当系统增长到一定程度的时候,会发现这个系统太庞大了,改减减肥了。比如说,我们会考虑类似“微内核”的思路,把周边的一些东西尽可能剔除出去。这样做有几个巨大的好处:第一,系统复杂度随着解耦而降低;第二,能够更容易分解开发组,降低管理的难度;第三,部署也会解耦而相应的简化。关于第三点,我稍微多说一点点:以前某个功能的升级可能要整个系统测一遍才能上线,甚至可能这个功能本身测过已经没有问题的,但是系统中的其他部分还有Bug,导致用户迫切需要的这个功能迟迟无法上线。如果我们把他们拆出来,这个问题就会得到巨大的简化。

那么,当我们拆出来很多小服务之后,就涉及到这些小服务和核心的连接,通常还是离不开配置。除了配置本身,还有另外一个细节需要考虑到,而这个通常是我们比较容易忽略的部分——版本。我这里所说到的版本,可以是指前面说到的alpha/beta/rc/release等版本,还可以是指面向不同客户的的版本。后者可能需要给一个具体的例子,大家才好理解:

比如说,我是一个Blog引擎服务提供商,通过定制就可以提供Blog的Hosting服务。比如说,新浪说要这样这样的样式和功能,我这边一配置就出来了;猫扑说要那样那样的风格和服务,我一配置也出来了。假设这个Blog引擎可能是跑在我的服务器上,而不是安装在新浪或者猫扑的服务器上,也可能安装在对方机器上,这个假设很重要,这么做的理由可能是:可以控制我的无形资产;或者是节约对方的成本;或者是部署方便,等等。然后呢,也为了提供“快照”功能,我们需要些一个小服务,这个小服务会定时的直接抓取系统中的数据,然后以文件或者数据库的形式缓存下来。很显然,新浪和猫扑不太可能用同一个数据库来存放Blog数据,因此这个小服务抓取出来的内容可能key值相同,但数据不一样,因此至少这些缓存信息也应该独立存放。通常,我们的设计都是只有一个数据库连接配置——简单啊,不容易出错;要访问不同的数据库通常也是互相独立的,因此分别部署就好了,那么快照服务很可能是分别部署的。好了,考虑后来又有“慢照”、“连续照”、“不照”、“什么照”等一系列周边服务,这些服务也要独立部署,那么问题就来了:

你的部署过程将会使一个n*m的关系,n个小服务对应m个内核。这是十分痛苦的,只要有一个地方配置错了,很可能就会出现安全泄露,或者数据互相串扰等严重的问题。 如果我们稍微考虑一下,通常这些小服务除了版本差异的地方之外,其它的差异都会比较小,比如对于同一个服务来说,程序代码通常只要有一套就可以了。因此,我们应用以下原则可以减少部署的困难:

提供一个底层的框架,能够识别不同的(内核)版本,根据不同的版本能够读取不同的配置;

如果能够把这个过程变成对服务本身是透明的,则更为理想——这意味着你不需要给开发服务的人员讲解过多的细节,以及便于把旧的代码迁移过来。

除此之外,我们还会发现一个问题,就是随着服务的增多,部署仍然是一个困难的事情,尤其是涉及的迁移的时候。比如说,我们发现猫扑访问量很大,需要把周边服务迁移到一个独立的机器去运行。于是乎我们要找到每一个服务所在的目录,复制到新的服务器上,同时分别修改这些服务的配置,甚至是文件系统的权限等。此外核心的配置可能也发生了变化——需要修改有关服务所在位置的配置信息。考虑到这个问题,我们还可以应用以下原则来减少这部分的困难:

尽量将周边的一些小服务集中起来,同时提供一个底层框架,能够根据正在使用的服务读取不同的配置;

如果这个过程是透明的则更理想——理由同上。


当我们应用了这两个原则之后,我们就可以把周边服务的部署过程,从n*m转变为n,甚至是1的程度。当然,开发不会因此简化,甚至可能会变得复杂一些——要额外开发一个底层框架出来。不过我想先这个额外的开发,其复杂度还是相对较低的,带来的好处确不少。


不知道我的这些想法,大家是否能够理解和认同?

 

posted on   Sumtec  阅读(2041)  评论(5编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
点击右上角即可分享
微信分享提示