与网络相关的文件:
1) /etc/sysconfig/network 设置主机名称及能否启动Network
2) /etc/sysconfig/network-scripts/ifcfg-eth0 设置网卡参数的文件
3) /etc/modprobe.conf 开机时用来设置加载内核模块的文件
4) /etc/resolv.conf 设置DNS IP(解析服务器)的文件
5) /etc/hosts 记录计算机IP对应的主机名称或主机别名
6) /etc/protocols 定义IP数据包协议的相关数据,包括ICMP、TCP方面的数据包协议的定义等
与网络相关的启动指令:
1)/etc/init.d/network restart 可以重启整个网络的参数
2)ifup eth0(ifdown eth0) 启动或是关闭某个网络接口,可以通过简单的script来处理,这两个script会主动到/etc/sysconfig/network-scripts/目录下
·ifconfig 查询、设置网卡与IP网段等相关参数
·ifup/ifdown 启动/关闭网络接口
配置IP的三种方法:
1、使用命令设置:
只是暂时修改网络接口,立即生效,但不永久有效
#ifconfig ethX ip/netmask
# ifconfig eth0 192.168.100.1 设置eth0的IP
# ifconfig eth0 192.168.100.1 netmask 255.255.255.0 > mtu 8000 设置网络接口值,同时设置MTU的值
2、 图形界面设置:
system-config-network-gui
system-config-network-tui
输入setup命令,进入图形界面(配置设备IP等相关属性信息、system-config中的服务集中在这一面板中),有时进入图形设置网络接口的界面时会出现乱码,这时的解决方法是:退出此图形界面,输入当命令“export LANG=en”,再进入图形界面,乱码便会得到改善。
进入图形界面,选择“Network configuration”
修改后网络接口之后,“Ok”、“Save”、“Save&Quit”、“Quit”退出,网络接口修改完成。网络接口不会立即生效,一旦生效,便会永久有效,让IP生效的解决方法是:
1. #ifdown eth1 && ifup eth1 先禁用,再启用
2. #service network restart 网络服务重启
3. #/etc/init.d/network restart 也可以重启网络接口
3、直接编辑配置文件:
#vim /etc/sysconfig/network-scripts/ifcfg-ethX
修改网络接口的配置文件,配置文件中的常用的属性有:
DEVICE=ethX 设备名
BOOTPROTO=(none | static(手动指定地址) | dhcp(动态获取) | bootp)
ONBOOT={yes | no} 系统启动时,网络设备是否被激活
HWADDR= 物理地址,不可随便改动
IPADDR= IP地址,必须
NETMASK= 子网掩码,必须
TYPE=Ethernet 默认的,一般不要改,此项可以不存在
常用属性还有:
GATEWAY= 网关
USERCTL={yes | no} 是否允许普通用户启用和禁用网络设备
PEERDNS={yes | no} 若使用dhcp获取地址,服务器分配一个IP地址,是否修改服务器DNS的默认指向(默认值为yes)
网络接口不会立即生效,一旦生效,便会永久有效,让IP生效的解决方法和第二种方法一样:
1. #ifdown eth1 && ifup eth1 先禁用,再启用
2. #service network restart 网络服务重启
3. #/etc/init.d/network restart 也可以重启网络接口
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
无论是
操作系统 (Unix 或者
Windows),还是应用程序 (Web 服务,
数据库系统等等) ,通常都有自身的日志机制,以便故障时追溯现场及原因。Windows Event Log和
SQL Server Error Log就是这样的日志, PS: SQL Server 中的错误日志 (Error Log) 类似于
Oracle中的alert 文件。
一. 错误日志简介
1. Windows事件日志与SQL Server 错误日志
Windows事件日志中,应用程序里的SQL Server和SQL Server Agent服务,分别对应来源自MSSQLSERVER和SQLSERVERAGENT的日志信息;
SQL Server错误日志中信息,与Windows事件日志里来源自MSSQLSERVER的日志信息基本一致,不同的是,Windows事件日志里信息为应用程序级,较为简洁些,而SQL Server错误日志里通常有具体的数据库错误信息。比如:
Windows事件日志中错误信息:
Login failed for user 'sa'. Reason: Password did not match that for the login provided. [CLIENT: 10.213.20.8]
SQL Server错误日志中错误信息:
Login failed for user 'sa'. Reason: Password did not match that for the login provided. [CLIENT: 10.213.20.8]
Error: 18456, Severity: 14, State: 8.
2. 如何理解SQL Server的Error message?
以上面的Error: 18456, Severity: 14, State: 8.为例:
(1) Error,错误编号,可以在系统表里查到对应的文本信息;
select * From sys.messages where message_id = 18456
(2) Severity,错误级别,表明这个错误的严重性,一共有25个等级,级别越高,就越需要我们去注意处理,20~25级别的错误会直接报错并跳出执行,用SQL语句的TRY…CATCH是捕获不到的;
(3) State,错误状态,比如18456错误,帮助文档记载了如下状态,不同状态代表不同错误原因:
1. Error information is not available. This state usually means you do not have permission to receive the error details. Contact your SQL Server administrator for more information.
2. User ID is not valid.
5. User ID is not valid.
6. An attempt was made to use a Windows login name with SQL Server Authentication.
7. Login is disabled, and the password is incorrect.
8. The password is incorrect.
9. Password is not valid.
11. Login is valid, but server access failed.
12. Login is valid login, but server access failed.
18. Password must be changed.
还有文档未记载的State: 10, State: 16,通常是SQL Server启动帐号权限问题,或者重启SQL Server服务就好了。
3. SQL Server 错误日志包含哪些信息
SQL Server错误日志中包含SQL Server开启、运行、终止整个过程的:运行环境信息、重要操作、级别比较高的错误等:
(1) SQL Server/Windows基本信息,如:版本、进程号、IP/主机名、端口、CPU个数等;
(2) SQL Server启动参数及认证模式、内存分配;
(3) SQL Server实例下每个数据打开状态(包括系统和用户数据库);
(4) 数据库或服务器配置选项变更,KILL操作,开关DBCC跟踪,登录失败等等
(5) 数据库备份/还原的记录;
(6) 内存相关的错误和警告,可能会DUMP很多信息在错误日志里;
(7) SQL Server调度异常警告、IO操作延迟警告、内部访问越界 (也就是下面说到的Error 0);
(8) 数据库损坏的相关错误,以及DBCC CHECKDB的结果;
(9) 实例关闭时间;
另外,可以手动开关一些跟踪标记(trace flags),来自定义错误日志的内容,比如:记录如用户登入登出记录(login auditing),查询的编译执行等信息,比较常用的可能是用于检查死锁时的1204/1222 跟踪标记。
通常错误日志不会记录SQL语句的性能问题,如:阻塞、超时的信息,也不会记录Windows层面的异常(这会在windows事件日志中记载)。
SQL Server Agent错误日志中同样也包括:信息/警告/错误这几类日志,但要简单很多。
4. SQL Server 错误日志存放在哪里
假设SQL Server被安装在X:\Program Files\Microsoft SQL Server,则SQL Server 与SQL Server Agent的错误日志文件默认被放在:
X:\Program Files\Microsoft SQL Server\MSSQL.n\MSSQL\LOG\ ERRORLOG ~ ERRORLOG.n
X:\Program Files\Microsoft SQL Server\MSSQL.n\MSSQL\LOG\SQLAGENT.n and SQLAGENT.out.
如果错误日志路径被管理员修改,可以通过以下某种方式找到:
(1) 操作系统的应用程序日志里,SQL Server启动时会留下错误日志文件的路径;
(2) 通过SSMS/管理/错误日志,SQL Server启动时会留下错误日志文件的路径;
(3) SQL Server配置管理器里,点击SQL Server实例/属性/高级/启动参数 (Startup parameters) ;
(4) 通过一个未记载的SQL语句 (在SQL Server 2000中测试无效,2005及以后可以):
SELECT SERVERPROPERTY('ErrorLogFileName')
5. SQL Server 错误日志目录下的其他文件
在错误日志目录下除了SQL Server和SQL Server Agent的日志,可能还会有以下文件:
(1) 维护计划产生的report文件 (SQL Server 2000的时候,后来的维护计划log记录在msdb);
(2) 默认跟踪(default trace) 生成的trace文件,PS: 审计(Audit) 产生的trace文件在\MSSQL\DATA下;
(3) 全文索引的错误、日志文件;
(4) SQLDUMP文件,比如:exception.log/SQLDump0001.txt/SQLDump0001.mdmp,大多是发生Error 0时DUMP出来的,同时在错误日志里通常会有类似如下记录:
Error: 0, Severity: 19, State: 0
SqlDumpExceptionHandler: Process 232 generated fatal exception c0000005 EXCEPTION_ACCESS_VIOLATION. SQL Server is terminating this process.
顺便说下ERROR 0 的解释:
You've hit a bug of some kind - an access violation is an unexpected condition. You need to contact Product Support (http://support.microsoft.com/sql) to help figure out what happened and whether there's a fix available.
Is your server up to date with service packs? If not, you might try updating to the latest build. This error is an internal error in sql server. If you are up to date, you should report it to MS.
二. 错误日志维护
1. 错误日志文件个数
1.1 SQL Server错误日志
SQL Server错误日志文件数量默认为7个:1个正在用的(ERRORLOG)和6个归档的(ERRORLOG.1 – ERRORLOG.6),可以配置以保留更多(最多99个);
(1) 打开到SSMS/管理/SQL Server Logs文件夹/右击/配置;
(2) 通过未记载的扩展存储过程,直接读写注册表也行:
USE [master]
GO
EXEC xp_instance_regwrite N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'NumErrorLogs', REG_DWORD, 50
GO
--Check current errorlog amout
USE [master]
GO
DECLARE @i int
EXEC xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'NumErrorLogs', @i OUTPUT
SELECT @i
SQL Server作为一个Windows下的应用程序,很多信息是写在注册表里的,自然也可以手动打开注册表编辑器或写SHELL去修改注册表来作配置。
最后,可以通过 如下SQL语句查看已存在的错误日志编号、起止时间、当前大小。
EXEC master..xp_enumerrorlogs
1.2 SQL Server Agent错误日志
SQL Server Agent错误日志文件数量共为10个:1个正在用的(SQLAGENT.OUT),9个归档的(SQLAGENT.1 - SQLAGENT.9),个数不可以修改,但可以配置日志所记载的信息类型:信息、警告、错误。
(1) 打开到SSMS/SQL Server Agent/Error Logs文件夹/右击/配置;
(2) 未记载的扩展存储过程:
USE [msdb]
GO
EXEC msdb.dbo.sp_set_sqlagent_properties @errorlogging_level=7
GO
至于@errorlogging_level各个值的意思,由于没有文档记载,需要自己测试并推算下。
2. 错误日志文件归档
2.1 为什么要归档错误日志?
假设SQL Server实例从来没被重启过,也没有手动归档过错误日志,那么错误日志文件可能会变得很大,尤其是有内部错误时会DUMP很多信息,一来占空间,更重要的是:想要查看分析也会不太方便。
SQL Server/SQL Server Agent 错误日志有2种归档方式,即:创建一个新的日志文件,并将最老的日志删除。
(1) 自动归档:在SQL Server/ SQL Server Agent服务重启时;
(2) 手动归档:定期运行如下系统存储过程
EXEC master..sp_cycle_errorlog; --DBCC ERRORLOG 亦可
EXEC msdb.dbo.sp_cycle_agent_errorlog;--SQL Agent 服务需在启动状态下才有效
2.2 可不可以根据文件大小来归档?
可能有人会觉得,虽然很久没归档,但是错误日志确实不大,没必要定期归档,最好可以根据文件大小来判断。有以下几种方法:
(1) 有些监控工具,比如:SQL Diagnostic manager,就有检测错误日志文件大小,并根据大小来决定是否归档的功能;
(2) 自定义脚本也可以,比如:powershell, xp_enumerrorlogs 都可以检查错误日志大小;
(3) SQL Server 2012支持一个注册表选项,以下语句限制每个错误日志文件为5M,到了5M就会自动归档,在2008/2008 R2测试无效:
USE [master]
GO
EXEC xp_instance_regwrite N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'ErrorLogSizeInKb', REG_DWORD, 5120;
三. 错误日志查看及告警
错误日志以文本方式记录,记事本就可以查看,如果错误日志很大,可以选择Gvim/UltraEdit /DOS窗口type errorlog等,这些方式都会“分页”加载,不会卡住。
1. 错误日志查看
SQL Server提供了以下2种方式查看:
(1) 日志查看器 (log viewer),除了可以查看SQL Server 与SQL Server Agent的错误日志,还可以查看操作系统日志、数据库邮件日志。不过当日志文件太大时,图形界面非常慢;
(2) 未记载的扩展存储过程xp_readerrorlog,另外还有一个名为sp_readerrorlog的存储过程,它是对xp_readerrorlog的简单封装,并且只提供了4个参数,直接使用xp_readerrorlog即可:
在SQL Server 2000里,仅支持一个参数,即错误日志号,默认为0~6:
exec dbo.xp_readerrorlog --写0或null都会报错,直接运行即可 exec dbo.xp_readerrorlog 1 exec dbo.xp_readerrorlog 6 --sql server 2000 read error log if OBJECT_ID('tempdb..#tmp_error_log_all') is not null drop table #tmp_error_log_all create table #tmp_error_log_all ( info varchar(8000),--datetime + processinfo + text num int ) insert into #tmp_error_log_all exec dbo.xp_readerrorlog --split error text if OBJECT_ID('tempdb..#tmp_error_log_split') is not null drop table #tmp_error_log_split create table #tmp_error_log_split ( logdate datetime,--datetime processinfo varchar(100),--processinfo info varchar(7900)--text ) insert into #tmp_error_log_split select CONVERT(DATETIME,LEFT(info,22),120), LEFT(STUFF(info,1,23,''),CHARINDEX(' ',STUFF(info,1,23,'')) - 1), LTRIM(STUFF(info,1,23 + CHARINDEX(' ',STUFF(info,1,23,'')),'')) from #tmp_error_log_all where ISNUMERIC(LEFT(info,4)) = 1 and info <> '.' and substring(info,11,1) = ' ' select * from #tmp_error_log_split where info like '%18456%' |
在SQL Server 2005及以后版本里,支持多达7个参数,说明如下:
exec dbo.xp_readerrorlog 1,1,N'string1',N'string2',null,null,N'desc'
参数1.日志文件号: 0 = 当前, 1 = Archive #1, 2 = Archive #2, etc...
参数2.日志文件类型: 1 or NULL = SQL Server 错误日志, 2 = SQL Agent 错误日志
参数3.检索字符串1: 用来检索的字符串
参数4.检索字符串2: 在检索字符串1的返回结果之上再做过滤
参数5.日志开始时间
参数6.日志结束时间
参数7.结果排序: N'asc' = 升序, N'desc' = 降序
--sql server 2005 read error log if OBJECT_ID('tempdb..#tmp_error_log') is not null drop table #tmp_error_log create table #tmp_error_log ( logdate datetime, processinfo varchar(100), info varchar(8000) ) insert into #tmp_error_log exec dbo.xp_readerrorlog select * from #tmp_error_log where info like '%18456%' |
2. 错误日志告警
可以通过对某些关键字做检索:错误(Error),警告(Warn),失败(Fail),停止(Stop),而进行告警 (database mail),以下脚本检索24小时内的错误日志:
declare @start_time datetime ,@end_time datetime set @start_time = CONVERT(char(10),GETDATE() - 1,120) set @end_time = GETDATE() if OBJECT_ID('tempdb..#tmp_error_log') is not null drop table #tmp_error_log create table #tmp_error_log ( logdate datetime, processinfo varchar(100), info varchar(8000) ) insert into #tmp_error_log exec dbo.xp_readerrorlog 0,1,NULL,NULL,@start_time,@end_time,N'desc' select COUNT(1) as num, MAX(logdate) as logdate,info from #tmp_error_log where (info like '%ERROR%' or info like '%WARN%' or info like '%FAIL%' or info like '%STOP%') and info not like '%CHECKDB%' and info not like '%Registry startup parameters%' and info not like '%Logging SQL Server messages in file%' and info not like '%previous log for older entries%' group by info |
当然,还可以添加更多关键字:kill, dead, victim, cannot, could, not, terminate, bypass, roll, truncate, upgrade, recover, IO requests taking longer than,但当中有个例外,就是DBCC CHECKDB,它的运行结果中必然包括Error字样,如下:
DBCC CHECKDB (xxxx) executed by sqladmin found 0 errors and repaired 0 errors.
所以对0 errors要跳过,只有在发现非0 errors时才作告警。
小结
如果没有监控工具,那么可选择扩展存储过程,结合数据库邮件的方式,作自动检查及告警,并定期归档错误日志文件以避免文件太大。大致步骤如下 :
(1) 部署数据库邮件;
(2) 部署作业:定时检查日志文件,如检索到关键字,发邮件告警;
(3) 部署作业:定期归档错误日志,可与步骤(2) 合并作为两个step放在一个作业里。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
vmstat一直以来就是linux/unix中进行性能监控的利器,相比top来说它的监控更加系统级,更侧重于系统整体的情况。
今天在学习vmstat的时候,突然想看看
数据库中的并行对于系统级的影响到底有多紧密,自己简单
测试了一下。
首先来看看vmstat的命令的解释。
可能大家并不陌生,如果需要每隔2秒,生成3次报告,可以使用vmstat 2 3
对于命令的输出解释如下:
r代表等待cpu事件的进程数
b代表处于不可中断休眠中的进程数,
swpd表示使用的虚拟内存的总量,单位是M
free代表空闲的物理内存总量,单位是M
buffer代表用作缓冲区的内存总量
cache代表用做高速缓存的内存总量
si代表从磁盘交换进来的内存总量
so代表交换到磁盘的内存总量
bi代表从块设备收到的块数,单位是1024bytes
bo代表发送到块设备的块数
in代表每秒的cpu中断次数
cs代表每秒的cpu上下文切换次数
us代表用户执行非内核代码的cpu时间所占的百分比
sy代表用于执行那个内核代码的cpu时间所占的百分比
id代表处于空闲状态的cpu时间所占的百分比
wa代表等待io的cpu时间所占的百分比
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 296716 399588 904276 0 0 0 16 639 1285 0 0 100 0 0 0 0 0 296576 399588 904276 0 0 43 11 809 1484 1 1 98 0 0 0 0 0 296576 399592 904276 0 0 53 25 764 1538 0 0 99 0 0 0 0 0 296584 399592 904276 0 0 0 11 716 1502 0 0 100 0 0 0 0 0 296584 399600 904276 0 0 21 16 756 1534 0 0 100 0 0 |
零零总总说了一大堆,我们举几个例子,一个是文件的拷贝,这个最直接的io操作。看看在vmstat的监控下会有什么样的数据变化。
黄色部分代表开始运行cp命令时vmstat的变化,我们拷贝的文件是200M,可以看到空闲内存立马腾出了将近200M的内存空间,buffer空间基本没有变化,这部分空间都放入了cache,同时从设备收到的块数也是急剧增加,cpu上下文的切换次数也是从930瞬间达到了1918,然后慢慢下降,cpu的使用率也是瞬间上升,最后基本控制在20%~30%。
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 296716 399588 904276 0 0 0 16 639 1285 0 0 100 0 0 0 0 0 296576 399588 904276 0 0 43 11 809 1484 1 1 98 0 0 0 0 0 296576 399592 904276 0 0 53 25 764 1538 0 0 99 0 0 0 0 0 296584 399592 904276 0 0 0 11 716 1502 0 0 100 0 0 0 0 0 296584 399600 904276 0 0 21 16 756 1534 0 0 100 0 0 0 0 0 296584 399600 904276 0 0 0 11 930 1625 1 1 98 0 0 1 1 0 93960 399608 1104528 0 0 33427 24 1918 2094 0 23 71 7 0 1 0 0 66440 399592 1131832 0 0 7573 12 1513 1323 0 25 74 2 0 5 0 0 74988 399588 1123188 0 0 2859 33 887 594 0 24 75 1 0 11 0 0 74280 399572 1114952 0 0 1963 15 770 738 3 44 53 0 0 2 0 0 74492 399568 1125008 0 0 3776 16 1014 812 0 20 73 6 0 2 0 0 72640 399560 1126696 0 0 2411 23 975 619 1 21 78 0 0 1 0 0 70532 399556 1128936 0 0 2389 16 1018 732 0 22 77 0 0 2 0 0 75396 399532 1116288 0 0 2795 15 831 673 2 47 51 0 0 2 0 0 79576 399536 1121416 0 0 2901 20 850 688 1 24 63 12 0 0 3 0 67052 399536 1130252 0 0 1493 43708 701 644 0 29 24 47 0 1 0 0 74244 399540 1125600 0 0 1323 19 842 624 0 10 65 25 0 3 0 0 70788 399532 1127728 0 0 2539 21152 936 624 0 18 58 24 0 5 0 0 73164 399532 1120352 0 0 1109 27 458 447 4 71 17 9 0 0 0 0 76120 399532 1125684 0 0 1859 15 957 1182 0 19 80 1 0 0 0 0 76128 399532 1125688 0 0 21 19 679 1399 0 0 98 1 0 --拷贝 工作完成系统的负载又逐步恢复了原值。 |
对于文件的操作有了一个基本认识,来看看数据库级的操作吧。
首先看看全表扫描的情况。
我们对于一个170万数据的表进行查询。可以看到
从设备收到的块数是急剧增加,效果跟文件的拷贝有些类似,但是buffer,cache基本没有变化。我想这也就是数据库级别的操作和系统级别的根本区别吧。数据库的buffer_cache应该就是起这个作用的。
SQL> select count(*)from test where object_id<>1; COUNT(*) ---------- 1732096 [ora11g@rac1 arch]$ vmstat 3 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 1 0 0 166520 399680 1023292 0 0 17 20 6 5 1 1 98 1 0 0 0 0 175800 399680 1023292 0 0 53 11 680 1308 0 0 100 0 0 1 0 0 175800 399680 1023292 0 0 18021 24 1451 1826 2 7 66 25 0 0 0 0 175800 399680 1023292 0 0 53 53 812 1577 0 0 98 2 0 0 0 0 166256 399680 1023292 0 0 0 16 881 1614 1 1 98 0 0 1 0 0 175908 399680 1023292 0 0 21 11 866 1605 0 0 99 0 0 |
接着来做一个更为消耗资源的操作,这个sql不建议在正式环境测试,因为很耗费资源
对一个170多万的表进行低效的连接。vmstat的情况如下。运行了较长的时间,过了好一段时间都没有结束,可以看到cpu的使用率已经达到了40~50%,在开始的时候,从设备中得到的块数急剧增加,然后基本趋于一个平均值,buffer,cache基本没有变化。
SQL> select count(*)from test t1,test t2 where t1.object_id=t2.object_id; procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 176024 399688 1023292 0 0 43 11 655 1284 0 0 99 1 0 1 0 0 171420 399688 1023292 0 0 0 16 671 1302 1 1 98 0 0 0 0 0 176164 399688 1023292 0 0 0 11 735 1331 0 1 99 0 0 0 0 0 176164 399688 1023292 0 0 21 25 678 1291 0 0 99 0 0 1 0 0 173452 399688 1023292 0 0 15643 5256 1835 2178 6 12 76 6 0 2 0 0 163048 399688 1023292 0 0 15179 5748 2166 2271 7 12 67 14 0 1 0 0 172072 399688 1023292 0 0 5541 2432 2226 1860 32 6 59 3 0 1 0 0 169964 399688 1023292 0 0 656 24 2322 1656 46 1 50 4 0 1 0 0 169848 399688 1023292 0 0 485 11 2335 1637 48 1 50 2 0 1 0 0 159576 399692 1023288 0 0 448 115 2442 1738 49 1 48 2 0 1 0 0 169344 399692 1023292 0 0 712 11 2351 1701 47 1 50 3 0 1 0 0 169352 399696 1023288 0 0 619 24 2332 1649 48 1 49 2 0 1 0 0 169360 399696 1023292 0 0 467 11 2339 1623 47 1 50 2 0 1 0 0 159848 399700 1023288 0 0 693 16 2318 1673 48 1 48 3 0 1 0 0 169368 399700 1023292 0 0 467 11 2309 1660 47 1 50 3 0 2 0 0 169368 399700 1023292 0 0 467 28 2329 1624 48 1 50 2 0 |
来看看并行的效果。最后返回的条数有近亿条,这也就是这个连接低效的原因所在,但是在vmstat得到的信息来看和普通的数据查询还是有很大的差别。
首先是急剧消耗io,同时从内存中也取出了一块内存空间。然后io基本趋于稳定,开始急剧消耗cpu资源。可以看到cpu的使用率达到了90%以上。
SQL> select count(*)from test t1,test t2 where t1.object_id=t2.object_id; COUNT(*) ---------- 221708288 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 175048 399748 1023292 0 0 0 20 665 1274 0 0 100 0 0 0 0 0 175048 399748 1023292 0 0 21 11 657 1286 0 0 100 0 0 0 0 0 165644 399748 1023292 0 0 0 16 715 1310 1 1 98 0 0 0 0 0 175056 399748 1023292 0 0 0 11 664 1284 0 0 99 0 0 0 0 0 175056 399748 1023292 0 0 21 24 640 1289 0 0 99 0 0 0 4 0 142364 399748 1025408 0 0 5957 988 1407 1869 10 8 64 18 0 0 0 0 132092 399748 1025444 0 0 12520 4939 1903 2556 14 11 32 43 0 0 2 0 140248 399748 1025444 0 0 10477 3973 1728 2427 11 7 29 53 0 2 0 0 136776 399748 1025444 0 0 7987 4125 1536 2248 11 6 24 60 0 2 0 0 136776 399748 1025444 0 0 971 20 2427 1663 98 1 0 1 0 2 0 0 121404 399748 1025456 0 0 1160 11 2422 1730 96 3 0 1 0 2 0 0 134528 399748 1025460 0 0 1195 17 2399 1695 97 2 0 2 0 3 0 0 134520 399748 1025460 0 0 1325 19 2443 1693 96 1 0 3 0 2 0 0 134536 399748 1025460 0 0 1176 16 2405 1674 99 1 0 0 0 2 0 0 125108 399748 1025460 0 0 1139 11 2418 1647 97 2 0 1 0 2 0 0 134628 399752 1025460 0 0 1235 16 2391 1653 98 1 0 1 0 3 0 0 134644 399752 1025460 0 0 1197 21 2392 1640 97 2 0 1 0 2 0 0 134652 399756 1025460 0 0 1400 16 2433 1670 97 1 0 3 0 2 0 0 125116 399756 1025460 0 0 1008 11 2199 1564 97 2 0 1 0 |
看来并行的实现还是有很多的细节,相比普通的查询来说更加复杂,而且消耗的资源更多,这个也就是在使用并行的时候需要权衡的一个原因。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
一 磁盘物理结构
(1) 盘片:硬盘的盘体由多个盘片叠在一起构成。
在硬盘出厂时,由硬盘生产商完成了低级格式化(物理格式化),作用是将空白的盘片(Platter)划分为一个个同圆心、不同半径的磁道(Track),还将磁道划分为若干个扇区(Sector),每个扇区可存储128×2的N次方(N=0.1.2.3)字节信息,默认每个扇区的大小为512字节。通常使用者无需再进行低级格式化操作。
(2) 磁头:每张盘片的正反两面各有一个磁头。
(3) 主轴:所有盘片都由主轴电机带动旋转。
(4) 控制集成电路板:复杂!上面还有ROM(内有软件系统)、Cache等。
二 磁盘如何完成单次IO操作
(1) 寻道
当控制器对磁盘发出一个IO操作命令的时候,磁盘的驱动臂(Actuator Arm)带动磁头(Head)离开着陆区(Landing Zone,位于内圈没有数据的区域),
移动到要操作的初始数据块所在的磁道(Track)的正上方,这个过程被称为寻道(Seeking),对应消耗的时间被称为寻道时间(Seek Time);
(2) 旋转延迟
找到对应磁道还不能马上读取数据,这时候磁头要等到磁盘盘片(Platter)旋转到初始数据块所在的扇区(Sector)落在读写磁头正下方之后才能开始读取数据,在这个等待盘片旋转到可操作扇区的过程中消耗的时间称为旋转延时(Rotational Latency);
(3) 数据传送
接下来就随着盘片的旋转,磁头不断的读/写相应的数据块,直到完成这次IO所需要操作的全部数据,这个过程称为数据传送(Data Transfer),对应的时间称为传送时间(Transfer Time)。完成这三个步骤之后单次IO操作也就完成了。
根据磁盘单次IO操作的过程,可以发现:
单次IO时间 = 寻道时间 + 旋转延迟 + 传送时间
进而推算IOPS(IO per second)的公式为:
IOPS = 1000ms/单次IO时间
三 磁盘IOPS计算
不同磁盘,它的寻道时间,旋转延迟,数据传送所需的时间各是多少?
1. 寻道时间
考虑到被读写的数据可能在磁盘的任意一个磁道,既有可能在磁盘的最内圈(寻道时间最短),也可能在磁盘的最外圈(寻道时间最长),所以在计算中我们只考虑平均寻道时间。
在购买磁盘时,该参数都有标明,目前的SATA/SAS磁盘,按转速不同,寻道时间不同,不过通常都在10ms以下:
2. 旋转延时
和寻道一样,当磁头定位到磁道之后有可能正好在要读写扇区之上,这时候是不需要额外的延时就可以立刻读写到数据,但是最坏的情况确实要磁盘旋转整整一圈之后磁头才能读取到数据,所以这里也考虑的是平均旋转延时,对于15000rpm的磁盘就是(60s/15000)*(1/2) = 2ms。
3. 传送时间
(1) 磁盘传输速率
磁盘传输速率分两种:内部传输速率(Internal Transfer Rate),外部传输速率(External Transfer Rate)。
内部传输速率(Internal Transfer Rate),是指磁头与硬盘缓存之间的数据传输速率,简单的说就是硬盘磁头将数据从盘片上读取出来,然后存储在缓存内的速度。
理想的内部传输速率不存在寻道,旋转延时,就一直在同一个磁道上读数据并传到缓存,显然这是不可能的,因为单个磁道的存储空间是有限的;
实际的内部传输速率包含了寻道和旋转延时,目前家用磁盘,稳定的内部传输速率一般在30MB/s到45MB/s之间(服务器磁盘,应该会更高)。
外部传输速率(External Transfer Rate),是指硬盘缓存和系统总线之间的数据传输速率,也就是计算机通过硬盘接口从缓存中将数据读出交给相应的硬盘控制器的速率。
硬盘厂商在硬盘参数中,通常也会给出一个最大传输速率,比如现在SATA3.0的6Gbit/s,换算一下就是6*1024/8,768MB/s,通常指的是硬盘接口对外的最大传输速率,当然实际使用中是达不到这个值的。
这里计算IOPS,保守选择实际内部传输速率,以40M/s为例。
(2) 单次IO操作的大小
有了传送速率,还要知道单次IO操作的大小(IO Chunk Size),才可以算出单次IO的传送时间。那么磁盘单次IO的大小是多少?答案是:不确定。
操作系统为了提高 IO的性能而引入了文件系统缓存(File System Cache),系统会根据请求数据的情况将多个来自IO的请求先放在缓存里面,然后再一次性的提交给磁盘,也就是说对于数据库发出的多个8K数据块的读操作有可能放在一个磁盘读IO里就处理了。
还有,有些存储系统也是提供了缓存(Cache),接收到操作系统的IO请求之后也是会将多个操作系统的 IO请求合并成一个来处理。
不管是操作系统层面的缓存,还是磁盘控制器层面的缓存,目的都只有一个,提高数据读写的效率。因此每次单独的IO操作大小都是不一样的,它主要取决于系统对于数据读写效率的判断。这里以SQL Server数据库的数据页大小为例:8K。
(3) 传送时间
传送时间 = IO Chunk Size/Internal Transfer Rate = 8k/40M/s = 0.2ms
可以发现:
(3.1) 如果IO Chunk Size大的话,传送时间会变长,单次IO时间就也变长,从而导致IOPS变小;
(3.2) 机械磁盘的主要读写成本,都花在了寻址时间上,即:寻道时间 + 旋转延迟,也就是磁盘臂的摆动,和磁盘的旋转延迟。
(3.3) 如果粗略的计算IOPS,可以忽略传送时间,1000ms/(寻道时间 + 旋转延迟)即可。
4. IOPS计算示例
以15000rpm为例:
(1) 单次IO时间
单次IO时间 = 寻道时间 + 旋转延迟 + 传送时间 = 3ms + 2ms + 0.2 ms = 5.2 ms
(2) IOPS
IOPS = 1000ms/单次IO时间 = 1000ms/5.2ms = 192 (次)
这里计算的是单块磁盘的随机访问IOPS。
考虑一种极端的情况,如果磁盘全部为顺序访问,那么就可以忽略:寻道时间 + 旋转延迟 的时长,IOPS的计算公式就变为:IOPS = 1000ms/传送时间
IOPS = 1000ms/传送时间= 1000ms/0.2ms = 5000 (次)
显然这种极端的情况太过理想,毕竟每个磁道的空间是有限的,寻道时间 + 旋转延迟 时长确实可以减少,不过是无法完全避免的。
四 数据库中的磁盘读写
1. 随机访问和连续访问
(1) 随机访问(Random Access)
指的是本次IO所给出的扇区地址和上次IO给出扇区地址相差比较大,这样的话磁头在两次IO操作之间需要作比较大的移动动作才能重新开始读/写数据。
(2) 连续访问(Sequential Access)
相反的,如果当次IO给出的扇区地址与上次IO结束的扇区地址一致或者是接近的话,那磁头就能很快的开始这次IO操作,这样的多个IO操作称为连续访问。
(3) 以SQL Server数据库为例
数据文件,SQL Server统一区上的对象,是以extent(8*8k)为单位进行空间分配的,数据存放是很随机的,哪个数据页有空间,就写在哪里,除非通过文件组给每个表预分配足够大的、单独使用的文件,否则不能保证数据的连续性,通常为随机访问。
另外哪怕聚集索引表,也只是逻辑上的连续,并不是物理上。
日志文件,由于有VLF的存在,日志的读写理论上为连续访问,但如果日志文件设置为自动增长,且增量不大,VLF就会很多很小,那么就也并不是严格的连续访问了。
2. 顺序IO和并发IO
(1) 顺序IO模式(Queue Mode)
磁盘控制器可能会一次对磁盘组发出一连串的IO命令,如果磁盘组一次只能执行一个IO命令,称为顺序IO;
(2) 并发IO模式(Burst Mode)
当磁盘组能同时执行多个IO命令时,称为并发IO。并发IO只能发生在由多个磁盘组成的磁盘组上,单块磁盘只能一次处理一个IO命令。
(3) 以SQL Server数据库为例
有的时候,尽管磁盘的IOPS(Disk Transfers/sec)还没有太大,但是发现数据库出现IO等待,为什么?通常是因为有了磁盘请求队列,有过多的IO请求堆积。
磁盘的请求队列和繁忙程度,通过以下性能计数器查看:
LogicalDisk/Avg.Disk Queue Length
LogicalDisk/Current Disk Queue Length
LogicalDisk/%Disk Time
这种情况下,可以做的是:
(1) 简化业务逻辑,减少IO请求数;
(2) 同一个实例下的多个用户数据库,迁移到不同实例下;
(3) 同一个数据库的日志、数据文件,分离到不同的存储单元;
(4) 借助HA策略,做读写操作的分离。
3. IOPS和吞吐量(throughput)
(1) IOPS
IOPS即每秒进行读写(I/O)操作的次数。在计算传送时间时,有提到:如果IO Chunk Size大的话,那么IOPS会变小,假设以100M为单位读写数据,那么IOPS就会很小。
(2) 吞吐量(throughput)
吞吐量指每秒可以读写的字节数。同样假设以100M为单位读写数据,尽管IOPS很小,但是每秒读写了N*100M的数据,吞吐量并不小。
(3) 以SQL Server数据库为例
对于OLTP的系统,经常读写小块数据,多为随机访问,用IOPS来衡量读写性能;
对于数据仓库,日志文件,经常读写大块数据,多为顺序访问,用吞吐量来衡量读写性能。
磁盘当前的IOPS,通过以下性能计数器查看:
LogicalDisk/Disk Transfers/sec
LogicalDisk/Disk Reads/sec
LogicalDisk/Disk Writes/sec
磁盘当前的吞吐量,通过以下性能计数器查看:
LogicalDisk/Disk Bytes/sec
LogicalDisk/Disk Read Bytes/sec
LogicalDisk/Disk Write Bytes/sec
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
============问题描述============
在
数据库中存放用户发帖的信息,利用下面的程序得到该用户发帖的数量。可是UserUtils的值一直是1,这是怎么回事?
ResultSet res = sqlConn .executeQuery("select count(*) from" + username + "_message"); while (res.next()) { UserUtils.flag = res.getInt(1); System.out.println("userUtils = " + UserUtils.flag); } |
============解决方案1============
from这后面加个空格吧
============解决方案2============
select count(*) from后面少了一个空格样。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
数据库的备份是极其重要的事情。如果没有备份,遇到下列情况就会抓狂:
UPDATE or DELETE whitout where…
table was DROPPed accidentally…
INNODB was corrupt…
entire datacenter loses power…
从数据安全的角度来说,服务器磁盘都会做raid,
MySQL本身也有主从、drbd等容灾机制,但它们都无法完全取代备份。容灾和高可用能帮我们有效的应对物理的、硬件的、机械的故障,而对我们犯下的逻辑错误却无能为力。每一种逻辑错误发生的概率都极低,但是当多种可能性叠加的时候,小概率事件就放大成很大的安全隐患,这时候备份的必要性就凸显了。那么在众多的MySQL备份方式中,哪一种才是适合我们的呢?
常见的备份方式
MySQL本身为我们提供了mysqldump、mysqlbinlog远程备份工具,percona也为我们提供了强大的Xtrabackup,加上开源的mydumper,还有基于主从同步的延迟备份、从库冷备等方式,以及基于文件系统快照的备份,其实选择已经多到眼花缭乱。而备份本身是为了恢复,所以能够让我们在出现故障后迅速、准确恢复的备份方式,就是最适合我们的,当然,同时能够省钱、省事,那就非常完美。下面就我理解的几种备份工具进行一些比较,探讨下它们各自的适用场景。
1. mysqldump & mydumper
mysqldump是最简单的逻辑备份方式。在备份myisam表的时候,如果要得到一致的数据,就需要锁表,简单而粗暴。而在备份innodb表的时候,加上–master-data=1 –single-transaction 选项,在事务开始时刻,记录下binlog pos点,然后利用mvcc来获取一致的数据,由于是一个长事务,在写入和更新量很大的数据库上,将产生非常多的undo,显著影响性能,所以要慎用。
优点:简单,可针对单表备份,在全量导出表结构的时候尤其有用。
缺点:简单粗暴,单线程,备份慢而且恢复慢,跨IDC有可能遇到时区问题。
mydumper是mysqldump的加强版。相比mysqldump:
内置支持压缩,可以节省2-4倍的存储空间。
支持并行备份和恢复,因此速度比mysqldump快很多,但是由于是逻辑备份,仍不是很快。
2. 基于文件系统的快照
基于文件系统的快照,是物理备份的一种。在备份前需要进行一些复杂的设置,在备份开始时刻获得快照并记录下binlog pos点,然后采用类似copy-on-write的方式,把快照进行转储。转储快照本身会消耗一定的IO资源,而且在写入压力较大的实例上,保存被更改数据块的前印象也会消耗IO,最终表现为整体性能的下降。而且服务器还要为copy-on-write快照预留较多的磁盘空间,这本身对资源也是一种浪费。因此这种备份方式我们使用的不多。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
Hibernate 与数据库中的触发器协同工作时, 会造成两类问题 1、触发器使 Session 的缓存中的持久化对象与数据库中对应的数据不一致:触发器运行在数据库中, 它执行的操作对 Session 是透明的 Session 的
解决方案: 在执行完 Session 的相关操作后, 立即调用 Session 的 flush() 和 refresh() 方法, 迫使 Session 的缓存与数据库同步(refresh() 方法重新从数据库中加载对
象)
2、update() 方法盲目地激发触发器: 无论游离对象的属性是否发生变化, 都会执行 update 语句, 而 update 语句会激发数据库中相应的触发器
解决方案:在映射文件的的 <class> 元素中设置 select-before-update 属性: 当 Session 的 update 或 saveOrUpdate() 方法更新一个游离对象时, 会先执行 Select 语句, 获得当前游离对象在数据库中的最新数据, 只有在不一致的情况下才会执行 update 语句(没有用到触发器的时候一般的情况下最好不要设置,因为会降低效率的)
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
Java应用中抛出的空指针异常是解决空指针的最好方式,也是写出能顺利
工作的健壮程序的关键。俗话说“预防胜于治疗”,对于这么令人讨厌的空指针异常,这句话也是成立的。值得庆幸的是运用一些防御性的编码技巧,跟踪应用中多个部分之间的联系,你可以将Java中的空指针异常控制在一个很好的水平上。顺便说一句,这是Javarevisited上的第二个空指针异常的帖子。在上个帖子中我们讨论了Java中导致空指针异常的常见原因,而在本教程中我们将会
学习一些Java的编程技巧和最佳实践。这些技巧可以帮助你避免Java中的空指针异常。遵从这些技巧同样可以减少Java代码中到处都有的非空检查的数量。作为一个有经验的Java程序员,你可能已经知道其中的一部分技巧并且应用在你的项目中。但对于新手和中级开发人员来说,这将是很值得学习的。顺便说一句,如果你知道其它的避免空指针异常和减少空指针检查的Java技巧,请和我们分享。
这些都是简单的技巧,很容易应用,但是对代码质量和健壮性有显著影响。根据我的经验,只有第一个技巧可以显著改善代码质量。如我之前所讲,如果你知道任何避免空指针异常和减少空指针检查的Java技巧,你可以通过评论本文来和分享。
1) 从已知的String对象中调用equals()和equalsIgnoreCase()方法,而非未知对象。
总是从已知的非空String对象中调用equals()方法。因为equals()方法是对称的,调用a.equals(b)和调用b.equals(a)是完全相同的,这也是为什么程序员对于对象a和b这么不上心。如果调用者是空指针,这种调用可能导致一个空指针异常
Object unknownObject = null; //错误方式 – 可能导致 NullPointerException if(unknownObject.equals("knownObject")){ System.err.println("This may result in NullPointerException if unknownObject is null"); } //正确方式 - 即便 unknownObject是null也能避免NullPointerException if("knownObject".equals(unknownObject)){ System.err.println("better coding avoided NullPointerException"); } |
这是避免空指针异常最简单的Java技巧,但能够导致巨大的改进,因为equals()是一个常见方法。
2) 当valueOf()和toString()返回相同的结果时,宁愿使用前者。
因为调用null对象的toString()会抛出空指针异常,如果我们能够使用valueOf()获得相同的值,那宁愿使用valueOf(),传递一个null给valueOf()将会返回“null”,尤其是在那些包装类,像Integer、Float、Double和BigDecimal。
BigDecimal bd = getPrice();
System.out.println(String.valueOf(bd)); //不会抛出空指针异常
System.out.println(bd.toString()); //抛出 "Exception in thread "main" java.lang.NullPointerException"
3) 使用null安全的方法和库 有很多开源库已经为您做了繁重的空指针检查工作。其中最常用的一个的是Apache commons 中的StringUtils。你可以使用StringUtils.isBlank(),isNumeric(),isWhiteSpace()以及其他的工具方法而不用担心空指针异常。
//StringUtils方法是空指针安全的,他们不会抛出空指针异常 System.out.println(StringUtils.isEmpty(null)); System.out.println(StringUtils.isBlank(null)); System.out.println(StringUtils.isNumeric(null)); System.out.println(StringUtils.isAllUpperCase(null)); Output: true true false false |
但是在做出结论之前,不要忘记阅读空指针方法的类的文档。这是另一个不需要下大功夫就能得到很大改进的Java最佳实践。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
最近做程序,时不时需要自己去手动将sql语句直接写入到
Java代码中,写入sql语句时,需要注意几个小问题。
先看我之前写的几句简单的sql语句,自以为没有问题,但是编译直接报错。
String str = "insert into XXX(a,b,c) values ('"a.getA()"','"a.getB()"','"a.getC()"');";
研究了半天发现应该是连接字符串问题,第一次修改过后将赋值字段前后加“+”号来完成sql语句。改正后代码如下
String str = "insert into XXX(a,b,c) values ('"+a.getA()+"','"+a.getB()+"','"+a.getC()+"');";
原来在
数据库中给字段动态赋值需要以‘“+···+”’的方式来完成。好的,编译后成功,将运行的str的结果值放入sql数据库中
测试,没有问题,自以为一切ok了,结果运行时再次报错。这把自己困扰住了,反复测试,在数据库中用sql语句来对比,没有问题啊,现将我最后成功的代码放上来,大家看看有没有什么不同。
String str = "insert into XXX(a,b,c) values ('"+a.getA()+"','"+a.getB()+"','"+a.getC()+"')";
没错,就是最后的分号,原来在java语句中不能讲分号加入到普通的sql语句中,虽然在数据库中没有报错,但是在java中一定还是要注意这种小问题的。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
今天在优化一个功能的时候遇到了instr与substr函数,之前没有接触过这两个函数,但是今天无意中用到,一查才发现,真是实用的一对兄弟啊。
先来说说substr函数,这个函数返回的是字符串的一部分。
substr(string,start,length)
其中string参数为必须参数,要截取的字符串内容。
start为必须参数,为起始的位置,可以为正数也可以为负数,正数的话代表从在字符串的指定位置开始;负数代表从字符串结尾的指定位置开始;0代表在字符串中的第一个字符处开始。
length不是必须参数,为截取的长度,正数代表从 start 参数所在的位置向后返回字符个数;负数代表从字符串末端指定位置向前返回字符个数。
举个例子:
substr("Hello World!",2,1)返回的是e
substr("Hello World!",2)返回的是ello World!
substr("Hello World!",-2,1)返回的是d
substr("Hello World!",-2,-1)返回的是d!
instr( string1, string2, start_position,nth_appearance ) 函数返回要截取的字符串在源字符串中的位置。
string1源字符串,要在此字符串中查找。
string2要在string1中查找的字符串 。
start_position代表开始的位置。
nth_appearance代表要查找第几次出现的string2. 此参数可选,如果省略,默认为 1.如果为负数系统会报错。
举个例子:
instr("Hello World!","o")返回的是5
instr("Hello World!","o",1,2)返回的是8。解释一下,这句话代表"o"从字符串第一个位置开始查询,第二个“o”出现的位置。
很有用的两个函数呢
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters