单位的工作流系统是基于Windows Workflow Foundation开发的,很早就知道这个wwf用到了msdtc,可能会引起一系列调试的麻烦,但是在开发,以及第一次的安装部署和上线过程中,都很顺利,没有碰上什么棘手的问题,于是松了一口气,自以为麻烦都已经过去了。但是没想到的是,最近一次Web的搬迁,让我为这个问题整整折腾了两天时间,碰上了一堆的问题。
计算机软硬环境如下:
一个集群,两台机器,OS Windows 200,运行SQLServer 2000,称两台机器分别为s1和s2
一台服务器,OS Windows 2003,用作Web,称它为机器a
一台调试开发机器, OS Windows XP,称为机器c
问题是这样的
机器a是新安装的,打算用它来作web服务器。一路轻车熟路,windows server 2003,iis,将机器加入到域,将域帐号加入管理员组。
问题1:机器装好了,看了一下状态,嗯?怎么连.net framework 3.0都已经装好了?哦,可能是wsus直接推下来的,不管,直接上web,结果,网页出错。
解决:考虑是不是因为.net安装不正确,于是卸载这个不知道什么时候装上去的.net 2.0 和 3.0,准备重新安装。结果这一卸简单,但是装的时候, .net 3.0就再也装不了,总提示wcf无法安装,在msdn forum上找了半天,有类似的问题,但是似乎没有一个明确的解决方法,有一个说法是因为iis的问题,但是我把iis卸载了再装也无济于事。最后的解决很直接,也很无奈,我是直接格了重装系统,然后再装的。问题是解决了,但是不知道原因,有知道的tx是否可以共享一下。
问题2:重装后,拷贝web,设定权限,一切ok,在机器c上再次满怀希望的访问,结果,网页无法访问!!
解决:这次检查了一下,发现只有asp.net的网页无法访问,其他诸如.css的文件倒可以直接下载。查看了设置,发现iis下Web服务扩展里的asp.net v2.0.50727被禁止,这个简单,直接允许就可以了。然后网页可以正常访问。
问题3:网页可以正常访问了,于是最麻烦的问题也来了。先说了一下这个工作流的设计,它是用sqlserver来进行持久化的,因此在系统的运行过程中,存在两种访问sql的方式,一种是程序中直接用代码来访问sqlserver,另一种是wwf通过dtc来访问sql(猜想,没有证实)。在我们这个工作流系统的运行过程中,第一种代码访问sql一点问题也没有,但是似乎第二种访问出了问题,wwf无法读取已经持久化的state。在组件服务里面,分布式事务处理协调器的事务统计数据中,全部是被中止的事务,提交量是0,也就是,机器a无法读取数据库中的数据。
解决尝试1:一开始怀疑是机器a上dtc设置的问题,于是参照机器c,也就是那台用来开发的计算机的设置,来折腾了一番,发现问题没有丝毫的改进。(注:机器c上工作流是正常的,并且和a是用的同一台数据)
解决尝试2:奇怪了,一样的设置,怎么会有问题,仔细看了一下,a上的dtc版本是5.x,比c上的3.x高,于是就想重装个低版本的dtc(老思路了),无奈网上没找到低版本的dtc,只好作罢。
解决尝试3:那会不会是因为集群上dtc 的设置问题呢?应该不会吧,要不然怎么c能正常用。死马当成活马医,在集群上面查找dtc 的设置,结果发现,这个dtc版本更低,只有非常少的一些设置,根本不需要也无法改什么东西。
解决尝试4:到网上搜了一下windows server 2003和 dtc有关的东西,发现了中文网站上大都是同一个内容(天下文章一大抄啊),就是讲了dtc中安全配置中的设置,而这个讲解对目前的情况没有任何帮助。
解决尝试5:msdn forum上提到了可能是因为防火墙阻挡dtc引起的问题事务失败,于是检查了a的设置,发现防火墙服务没有启动……于是启动,并且把防火墙关闭,故障依旧。不死心,把防火墙打开,并用 netsh firewall set allowed %windir%\system32\msdtc.exe enable 命令在防火墙上开放dtc的自由访问,结果故障依旧。
解决尝试6:网上有改注册表的,在TurnOffRpcSecurity这个项目上反复折腾的,照旧做了一遍,故障依旧
解决尝试7:网上说是不是因为dtc的启动帐户不对,查看了一下,a和c都是NT AUTHORITY\NetworkService启动的,而集群上比较老,是本地帐户启动的,那为什么c上正常而a上不正常呢,理智提醒我不要在这个问题上多做纠缠,于是没进一步探究下去。
解决尝试8:还有个说法是跨域之间的dtc可能会有问题。这个集群是属于域D1,而a和c都加入了D2,倒是符合这个说话,但是还是老问题,c上是正常的,所以也没多想。
最终解决:最后好像还是在msdn forum上,有人提到了dtcping这个工具,建议用它来看一下两台机器之间是否通畅。于是下载下来用了一下,果然,问题来了。在a和s1(s1是sqlserver服务所在的机器)直接互ping的过程中,a到s1是正常的,但是s1到a不通,同样的做法在c和s1之间是完全正常和通畅的。于是直接在s1 的dos窗口中ping 机器a,发现解析出来的是一个与a不同的ip地址,怪不得!
原来机器a所使用的机器名曾经在域D1上被另一台机器使用过,而且用的是另一个ip地址,现在a用了这个名字,并加入了域D2,但是这个解析在D1中一直没有更新,所以在D1域中机器直接ping a的名字就会解析到那台曾经用过的机器上,导致了dtc的单向不通。
既然找到了原因,也就好解决了,直接修改s1的hosts文件,硬性指向,然后a和s1就相互ping的通了。再试,…… 嗯???还有问题!!!一查,怎么dtc服务在s2上?sqlserver和dtc还不在同一个机器上。于是再改s2的hosts,再试…… 一切ok。
总结一下,这次的dtc失败主要是因为单向的通讯故障导致的,但一开始没想到这点,也走了不少弯路,希望本次的经历也能给大家一点帮助。
另外附上所用到的dtcping工具
/Files/oop/DTCPing.rar