安装最新补丁之后Cluster Service无法启动

一组双节点的Windows 2003群集,配合IBM DS4300磁盘阵列,安装了SQL Server 2000,A机安装完最新的安全补丁之后,将此节点上的SQL Server 2000服务切换到B机,重启A机之后发现Cluster Service无法启动,使用事件查看器检查系统日志,发现有以下错误记录:

Event Type: Warning
Event Source: ql2300
Event Category: None
Event ID: 118
Date: 2008-6-11
Time: 20:10:42
User: N/A
Computer: IAMS-DB2-1
Description:
The driver for device \Device\Scsi\ql23001 performed a bus reset upon request.

Event Type: Error
Event Source: ClusSvc
Event Category: Startup/Shutdown
Event ID: 1009
Date: 2008-6-11
Time: 20:11:19
User: N/A
Computer: IAMS-DB2-1
Description:
Cluster service could not join an existing server cluster and could not form a new server cluster. Cluster service has terminated.

Event Type: Error
Event Source: Service Control Manager
Event Category: None
Event ID: 7031
Date: 2008-6-11
Time: 20:11:20
User: N/A
Computer: IAMS-DB2-1
Description:
The Cluster Service service terminated unexpectedly. It has done this 3 time(s). The following corrective action will be taken in 240000 milliseconds: Restart the service.

开始怀疑是磁盘阵列状态迁移记录问题,类似的问题原来遇到过(read.php?549),本计划找机房的同事协助将两个节点和磁盘阵列都关闭,然后先开磁盘阵列,再开一个节点,正常后,最后再开另外一个节点。但这个准备作为最后一招,先看能不能远程解决。

先将节点A又重启,群集服务依然无法启动;在节点A中进入设备管理器,将RDAC Muti-Path Pseudo-Bus和两个QLogic QLA2340 PCI Fiber Channel Adapter禁用,重启节点A之后再启用这些设备,还是无效。

在正常启动的节点B上检查,突然发现在资源管理器中只看到SQL Server群集组下面的一个磁盘分区,本来是绑定了两个的。在磁盘管理中可以看到对应的几个分区,进入命令行,切换盘符到这个看不到的分区,提示驱动器没有准备好,在SQL Server企业管理器中尝试打开一些数据文件放在这个看不到分区的时候,企业管理器出现挂死状态,在群集管理器中看到SQL Server组自动脱机又重新联机,再查看之前有问题的那个分区,竟然正常了。再重启节点A,群集服务正常启动,也正常加入了群集,各个应用组切换也正常,问题消失。

最后检查之前出现问题的磁盘,发现里面有两个补丁安装文件的临时目录,考虑到补丁安装需要重启,且这些目录没有被正常清除掉,所以判断引起故障的原因是安装的补丁占用了SQL Server一个分区作为临时文件存放,安装之后某些文件挂起,需要重启之后才能被清理,但是这时又将节点A上的应用切换到了B上,导致这个磁盘未能被节点B正常获取(或者是某些资源状态),进而在节点A启动的时候,群集也在尝试抓取这个分区,导致出现“The driver for device \Device\Scsi\ql23001 performed a bus reset upon request.”错误,群集服务也就无法正常启动。

最后总结就一句话:群集上安装补丁,先将此节点上的全部应用组全部转移走后,再进行补丁安装!

PS. 如果采用之前准备的最后一招,我想应该也是可以解决这个问题的。

重新编译存储过程、触发器,刷新视图

SQL Server中存储过程和触发器一般只会在初次编译时进行优化,之后如果相关的索引或数据库统计发生变化后,已编译的存储过程和触发器不会随之更新优化,可能会导致执行效率低下甚至失效,解决方法:
1、删除重新创建存储过程或触发器,也可以用ALTER方法代替
2、SQL Server提供了sp_recompile用于设置强制编译标识,存储过程或者触发器下次被使用的时候会先重新编译定制优化
3、在创建存储过程的时候使用WITH_RECOMPILE选项,指明不创建优化计划缓存,在每次执行之前都重新编译,但这个会导致存储过程执行数据缓慢;

类似,有时修改完表之后,与之关联视图也有可能不会自动刷新,导致出现一些奇观的问题,例如查询出来的数据列是错位的等,解决方法:
1、删除重新创建视图,也可以用ALTER方法提到
2、SQL Server提供了sp_refreshview方法强制刷新视图

为了自己方便,写了一个自动获取整个数据库中所有数据库实例中用户创建的的存储过程、触发器和视图进行强制刷新的SQL,可将其添加到数据库的JOB中周期执行:

--重新编译存储过程、触发器
use tempdb
go

--create temp table
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[gmcc_recompile_info]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
delete from gmcc_recompile_info
else
create table gmcc_recompile_info
(
dbname varchar(255),
objtype varchar(255),
objowner varchar(255),
objname varchar(255)
)
GO

--get all store procdure info
declare @dbname as varchar(255)

declare xx cursor for
select name from master.dbo.sysdatabases

open xx
fetch next from xx into @dbname
while @@fetch_status = 0
begin

exec('use [' + @dbname + '] insert into tempdb.dbo.gmcc_recompile_info select ''' + @dbname + ''', xtype, sysusers.name, sysobjects.name from sysobjects left join sysusers on sysobjects.uid=sysusers.uid where (xtype=''P'' or xtype=''TR'' or xtype=''V'') and category=0');

fetch next from xx into @dbname
end
close xx
DEALLOCATE xx

--set recompile
declare @objtype as varchar(255)
declare @objowner as varchar(255)
declare @objname as varchar(255)

declare yy cursor for
select dbname, objtype, objowner, objname from tempdb.dbo.gmcc_recompile_info

open yy
fetch next from yy into @dbname, @objtype, @objowner, @objname
while @@fetch_status = 0
begin

if @objtype='P' --storeprocedure
exec('use [' + @dbname + '] exec sp_recompile ''[' + @objowner + '].[' + @objname + ']''')

else if @objtype='TR' --trigger
exec('use [' + @dbname + '] exec sp_recompile ''[' + @objowner + '].[' + @objname + ']''')

else if @objtype='V' --view
exec('use [' + @dbname + '] exec sp_refreshview ''[' + @objowner + '].[' + @objname + ']''')


fetch next from yy into @dbname, @objtype, @objowner, @objname
end

close yy
DEALLOCATE yy


--drop temp table
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[gmcc_recompile_info]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table gmcc_recompile_info
GO


上述SQL存在两个问题尚未解决:
1、由于sp_refreshview刷新视图的及时执行的,如果由于数据库表发生变化,导致某个视图刷新失败的话,整个过程就会停止下来,导致后面的刷新不能进行;
2、不支持数据库名称包含中文的情况

数据库维护计划,优化,错误1934

SQL Server 2000,利用数据库维护计划创建了周期性的数据库优化作业(Job),但是发现在对于某些数据库或者某些有计算列的表格进行索引重建的时候,会出现错误,例如日志文件中出现:

正在为表“ApplicationChannel”重建索引
[Microsoft SQL-DMO (ODBC SQLState: 42000)] 错误 1934: [Microsoft][ODBC SQL Server Driver][SQL Server]DBCC 失败,因为下列 SET 选项的设置不正确: 'QUOTED_IDENTIFIER, ARITHABORT'。


查询MSDN发现对应问题的KB,这个KB还是看英文的好,中文是自动翻译的有点诡异看不懂:http://support.microsoft.com/kb/902388/en-us

解决的方法就是打开对应的作业,修改“步骤”中的SQL语句,增加两个参数,例如(绿色部分为增加):
EXECUTE master.dbo.xp_sqlmaint N'-S IAMS-DB2-SQL -PlanID 6961E2D5-113D-4091-8BFD-A46E1B4BD117 -Rpt "\\10.244.16.76\h$\db_files_backup\每周数据库维护0.txt" -DelTxtRpt 6WEEKS -WriteHistory  -RebldIdx 30 -SupportComputedColumn'

其中对于计算列的支持开关-SupportComputedColumn,修改需要SQL Server 2000 + SP4支持。

开年不利

下午4点回到广州,打扫完卫生,洗完澡,9点了;习惯性检查系统有没有什么异常,一看不要紧,发现有个平台的数据库群集已经挂掉,远程找问题,查资料,折腾了1个小时搞不定,于是抓技术资源,11点多2人奔机房,检查硬件,检查软件,又是2个小时,还是没搞定,最后死马当活马医,重启磁盘阵列(个人认为这个动作风险较高,谁知道又会......),但是问题就是这样奇迹般的解决了。

TNND!


---故障回顾---

两台Dell PE6850安装Windows 2003 R2系统和一台IBM DS4300组成SQL Server群集,检查时发现群集管理器显示群集一直是正在切换状态,一直是沙漏图标,数据库服务无法启动,重启服务器后发现群集服务Cluster Service无法启动,事件查看器中有以下日志:
Event Type: Error
Event Source: ClusSvc
Event Category: Startup/Shutdown
Event ID: 1009
Date: 2007-2-25
Time: 0:15:53
User: N/A
Computer: IAMS-DB2-1
Description:
Cluster service could not join an existing server cluster and could not form a new server cluster. Cluster service has terminated.


检查%SYSTEMROOT%\Cluster\Cluster.log发现有以下错误记录:
...
ERR Physical Disk <Disk Q:>: [DiskArb] Reserve completed, status 170.
...
ERR [FM] FmGetQuorumResource failed, error 170.
ERR [INIT] ClusterForm: Could not get quorum resource. No fixup attempted.
Status = 5086
INFO [INIT] Cleaning up failed form attempt.
ERR [INIT] Failed to form cluster, status 5086.
...
ERR [CS] Service Stopped. exit code = 5086
ERR [RM] Active Resource = 00000000
ERR [RM] Resource State is 1, ""
...


重启单台服务器无效;
关闭一台服务器,单独启动另外一台服务器,无效;
用错误编号google搜索,按照一些文章指引,做了组策略本地策略的调整,做了一些配置修改,无效;
关闭了Cluster Disk Driver,重启服务器之后可以看到阵列上的各个分区,读取数据正常,再加上检查了硬件和光纤连线,无告警和异常,所以一直认为不是硬件问题;

最后还是想到日志中主要描述的问题是仲裁资源无法获取,所以还是想从共享磁盘下手,最后不得已重启磁盘阵列,结果发现之后群集服务就正常了。

此次问题可能是由于群集在切换中出现某些问题(为什么会自动切换了,暂时没发现问题),导致服务器上安装的IBM RDAC软件与磁盘阵列控制器通讯发生问题,造成控制器某些状态的挂死,重启导致群集服务无法正常获取仲裁磁盘数据,也就无法启动了。

无法添加、更新或删除从MSX服务器上发起的作业(或其步骤或调度)

当修改、删除该作业的时候SQL SERVER提示错误如下:“错误14274:无法添加、更新或删除从MSX服务器上发起的作业(或其步骤或调度)。”

如果SQL Server服务器改过机器名, 管理是旧名称时建立的job的时候可能会遇到这个错误,可这样处理:
use msdb
select * from sysjobs

update sysjobs set originating_server=SEVER_NAME'
where job_id='JOB_ID


如果出错,不允许update,可以尝试先执行
SP_CONFIGURE 'ALLOW UPDATES',1 RECONFIGURE WITH OVERRIDE
再update,之后别忘记
SP_CONFIGURE 'ALLOW UPDATES',0 RECONFIGURE WITH OVERRIDE

错误15023:当前数据库中已存在用户或角色

在迁移测试平台数据库的过程中发现,在两台服务器上运行的sql server 服务器之间迁移数据库的之后,会出现一个在源服务器上可以正常的用户在目的服务器上无法登录的情况。几经排常找到了原因与解决方法,因为这个问题与解决方法均比较复杂,所以把这个过程中的一些经验纪录下来与大家分享,希望能对大家以后的类似操作有所帮助。

首先介绍一下sql server中“登录”与“用户”的区别,“登录”用于用户身份验证,而数据库“用户”帐户用于数据库访问和权限验证。登录通过安全识别符 (SID) 与用户关联。将数据库恢复到其他服务器时,数据库中包含一组用户和权限,但可能没有相应的登录或者登录所关联的用户可能不是相同的用户。这种情况被称为存在“孤立用户”。 此时是不能通过新建登录或者是对同名登录授予对应数据库的“用户”权限来解决登录问题,因为SQL Server会报出“错误15023:当前数据库中已存在用户或角色”,为了解决这个问题,需要调用系统存储过程sp_change_users_login,具体用法如下:

Use Northwind
go
sp_change_users_login 'update_one', 'test', 'test'

其中Northwind为存在孤立用户的数据库,update_one是存储过程的参数,表示只处理一个用户,前一个test是“用户”,后一个test是“登录”,以上这个SQL表示将服务器登录“test”与 Northwind 数据库用户“test”重新连接起来。这样就可以正常使用数据库了。


以上是我的同事海涛的研究成果,贡献出来大家分享。

SQL Server 2000全文索引无法填充

一台SQL Server 2000服务器,已经启动了Microsoft Search服务,且可以正常的添加全文索引类别和表,确认也已经在数据库上设置了允许全文索引:
select fulltextserviceproperty ('IsFullTextInstalled')
select databaseproperty('edms','isfulltextenabled')


创建全文索引的语句似乎也找不到什么错误: EM74.gif
exec sp_fulltext_database 'enable'
exec sp_fulltext_catalog 'StationAddress', 'create', 'N:\db_files\EDMS'
exec sp_fulltext_table 'tcStation', 'create', 'StationAddress', 'PK_TCSTATION'
exec sp_fulltext_column 'tcStation', 'Address', 'add'
exec sp_fulltext_table 'tcStation','activate'
exec sp_fulltext_catalog 'StationAddress', 'start_full'


但是在企业管理器中选择填充全文索引,提示成功之后,却无法搜索到任何数据:
select * from tcStation where contains(*, '天河')


检查发现对应全文索引分类StationAddress的“项目计数”始终为0,“唯一键计数”之中为1,显然是无数据填充成功;没头绪几天之后才想到看看系统日志,结果发现以下记录 EM79.gif
无法访问项目 <SQLServer SQL0001200005> 中的爬网起点 <MSSQL75://SQLServer/3da903ec>。错误: 800700e9 - 管道的另一端上无任何进程。
由于没有可访问的爬网起点,无法开始对项目 <SQLServer SQL0001200005> 的爬网操作。请解决此错误并重试。


最终发现解决方法 EM107.gif ,在SQL Server登陆中添加本地管理员组BUILTIN\Administrators可登陆,且服务器角色为“System Administrators”,数据库访问拥有对应数据库的所有者权限。
再次填充全文索引,问题解决,可以睡觉老~~~ EM23.gif

小节:该问题可能是由于数据库是采用集群方式安装,默认没有添加该用户组访问权限所致,检查单机安装的都是有的;或者是该帐号被人删除也难说。但是整个过程最郁闷的事情就是操作分明失败,但提示确实成功,虽然M$你老人家设计的是后台异步做填充,但也不要回答得这么干脆呀~~ EM34.gif