问题:
大概每隔两个星期左右,秋色园上服务器就会来一次CPU百分百,由于问题发生的概率极低,要它重现也难,所以只能意淫是内存太少的原故。
以前出现,远程上去结束掉进程,就正常了,悲剧的是最近秋色园VPS不知啥原因,经常远程不上去, 最后转转折折只能进VPS管理后台重启。
要遇上CPU百分百,又是需要机缘,所以一旦发生和遇到解决的时间差度大,就会造成服务器长时间打不开,后果大伙都懂的。。。
以前出现,远程上去结束掉进程,就正常了,悲剧的是最近秋色园VPS不知啥原因,经常远程不上去, 最后转转折折只能进VPS管理后台重启。
要遇上CPU百分百,又是需要机缘,所以一旦发生和遇到解决的时间差度大,就会造成服务器长时间打不开,后果大伙都懂的。。。
解决:
方法一:设置应用池CPU策略,达到N的时候自动回收进程(不实用,排除)
因为更新网站dll时,偶尔有顺时达到100%,可能就1-2秒,可能会导致回收到,如果再有偶尔,就会造成死循环了。
方法二:写个软件放上去,监控cpu如果持续1分钟,直接kill掉进程。(就这么招了。。。)
花了点时间,写了下代码,扔上去了,哟省事了。。。。
新建一个控制台。。。代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace IISCpuForServer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("监控IIS CPU w3wp 进程中,若100%,而自动结束该进程...");
Thread thread = new Thread(new ThreadStart(Run));
thread.IsBackground = true;
thread.Start();
Console.Read();
}
static void Run()
{
try
{
while (true)
{
Process[] procs = Process.GetProcessesByName("w3wp");//读取网站的进程
if (procs != null && procs.Length > 0)
{
foreach (Process pro in procs)
{
if (!pro.HasExited)
{
CheckPro(pro);
}
}
}
Thread.Sleep(TimeSpan.FromMinutes(5));//5分钟来一次。
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
}
static void CheckPro(Process pro)
{
int s = 0;//60秒。
int killTimes = 0;
//间隔时间(毫秒)
int interval = 1000;
//上次记录的CPU时间
TimeSpan prevCpuTime = TimeSpan.Zero;
while (true)
{
//当前时间
TimeSpan curTime = pro.TotalProcessorTime;
//间隔时间内的CPU运行时间除以逻辑CPU数量
double value = (curTime - prevCpuTime).TotalMilliseconds / interval / Environment.ProcessorCount * 100;
prevCpuTime = curTime;
if (s > 0)
{
if (value > 90 && value < 100)//cpu连续超过90% 50秒就杀。
{
killTimes++;
if (killTimes > 50)
{
Console.WriteLine(pro.Id + " 长期高CPU,秒杀...");
pro.Kill();
Thread.Sleep(TimeSpan.FromMinutes(3));
return;
}
}
else
{
killTimes = 0;
}
if (killTimes > 0)//只有cpu超过90%才打印文字
{
Console.WriteLine(pro.Id + " CPU:" + value + " -- killtimes:" + killTimes);
}
}
Thread.Sleep(interval);
if (s > 59)
{
s = -1;
break;
}
else
{
s++;
}
}
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace IISCpuForServer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("监控IIS CPU w3wp 进程中,若100%,而自动结束该进程...");
Thread thread = new Thread(new ThreadStart(Run));
thread.IsBackground = true;
thread.Start();
Console.Read();
}
static void Run()
{
try
{
while (true)
{
Process[] procs = Process.GetProcessesByName("w3wp");//读取网站的进程
if (procs != null && procs.Length > 0)
{
foreach (Process pro in procs)
{
if (!pro.HasExited)
{
CheckPro(pro);
}
}
}
Thread.Sleep(TimeSpan.FromMinutes(5));//5分钟来一次。
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
}
static void CheckPro(Process pro)
{
int s = 0;//60秒。
int killTimes = 0;
//间隔时间(毫秒)
int interval = 1000;
//上次记录的CPU时间
TimeSpan prevCpuTime = TimeSpan.Zero;
while (true)
{
//当前时间
TimeSpan curTime = pro.TotalProcessorTime;
//间隔时间内的CPU运行时间除以逻辑CPU数量
double value = (curTime - prevCpuTime).TotalMilliseconds / interval / Environment.ProcessorCount * 100;
prevCpuTime = curTime;
if (s > 0)
{
if (value > 90 && value < 100)//cpu连续超过90% 50秒就杀。
{
killTimes++;
if (killTimes > 50)
{
Console.WriteLine(pro.Id + " 长期高CPU,秒杀...");
pro.Kill();
Thread.Sleep(TimeSpan.FromMinutes(3));
return;
}
}
else
{
killTimes = 0;
}
if (killTimes > 0)//只有cpu超过90%才打印文字
{
Console.WriteLine(pro.Id + " CPU:" + value + " -- killtimes:" + killTimes);
}
}
Thread.Sleep(interval);
if (s > 59)
{
s = -1;
break;
}
else
{
s++;
}
}
}
}
}
最后插播个流行漫画:
SQL Server 的事务和锁(一)
最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
SELECT @findCount= COUNT (id) FROM MyTable WHERE [fk_related_id]=@Argument IF (@findCount > 0) BEGIN ROLLBACK TRANSACTION RETURN ERROR_CODE END INSERT INTO MyTable ([fk_related_id],…) VALUES (@Argument,…) COMMIT TRANSACTION RETURN SUCCESS_CODE |
在搞清楚这个问题的过程中做了不少的实验,与各位共享。这一篇是开篇,主要说明的是 SQL Server 的四种(其实还有别的)经典的事务隔离级别,以及在不同的隔离级别下锁的使用手段,以及所带来的不同的数据一致性。
SQL Server 中锁的种类(Schema操作就暂时不涉及了)
锁类型 | 描述 |
(Shared Lock) | 用于只读操作数据锁定 |
(Update Lock) | 用于数据的更新,在数据真正的需要更新的时候会申请升级为X锁。 |
X(Exclusive Lock) | 独占锁,用于数据的更改。 |
Key-Range Lock(稍后讨论) | 仅仅在 Serializable 隔离级别保护数据,以避免任何有可能使得本事务第二次读取信息产生错误的数据插入操作 |
各个事务隔离级别下锁的使用
SQL Server 中有四种事务隔离级别,具体的大家去参建 MSDN。下面列出在不同的事务隔离级别下这些锁是如何使用的:
隔离级别 | 读数据锁状态 | 写数据锁状态 | 锁持有时间 |
Read Uncommitted | 不获得任何锁 | 不获得任何锁 | |
Read Committed | 数据获得S锁 | 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; | 读完即释放,并不持有至事务结束。 |
Repeatable Read | 数据获得S锁 | 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; | 持有至事务结束 |
Serializable | 数据获得S锁,同时获得Key-Range锁。 | 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁,同时获得Key-Range锁。 | 持有至事务结束 |
我们可以利用这些知识形象说明各个隔离级别下的数据一致性:
Read Uncommitted 级别
(1)脏读
(2)更新丢失
(3)不可重复读
(4)幻读
Read Committed 级别
(1)脏读
(2)更新丢失
(3)不可重复读
(4)幻读
Repeatable Read 级别
(1)脏读
(2)更新丢失
(3)不可重复读
(4)幻读
Serializable 级别
(1)脏读
(2)更新丢失
(3)不可重复读
(4)幻读
我们从上图可以比较直观的看到以下的结论
脏读 | 更新丢失 | 不可重复读 | 幻读 | |
Read Uncommitted | 可能 | 可能 | 可能 | 可能 |
Read Committed | 不可能 | 可能 | 可能 | 可能 |
Repeatable Read | 不可能 | 不可能 | 不可能 | 可能 |
Serializable | 不可能 | 不可能 | 不可能 | 不可能 |
这一篇到此为止,下一篇详细介绍 Key-Range Lock 并分析开篇提到的死锁问题。
分类: Concurrent, SQL Server