SharedCache分析:服务端程序
2008-02-07 23:10 无常 阅读(3738) 评论(4) 编辑 收藏 举报SharedCache由3个主要的项目组成MergeSystem.Indexus.WinServiceCommon、MergeSystem.Indexus.WinService和MergeSystem.Indexus.Notify。WinService可以以Windows服务方式加载,也可以以控制台方式运行,如果注册为Windows服务,则可以通过MergeSystem.Indexus.Notify程序来了解其状态,若是以控制台方式运行,则运行时的信息会在控制台窗口中显示。当然也可以配置通过NLog.dll记录日志。
大部分的功能都封装在WinServiceCommon项目中,WinService项目只负责监听和数据中转,这个项目中只有几个文件,如图1。
Indexus是个windows服务,也是程序的入口点,其类图如图2。
图1 | 图2 |
图3 ShareCache服务端程序主流程 |
Indexus可以接受几个命令行参数/install /i /uninstall /u来安装或卸载windows服务,若想以控制台方式启动程序,可以使用/local参数,如:
MergeSystem.Indexus.WinService.exe /local
或直接使用相同目录中的几个批处理文件来执行。来看一下main函数:
{
Access Log Access Log
string optionalArgs = string.Empty;
if (args.Length > 0)
{
optionalArgs = args[0];
}
args Handling args Handling
}
这里可以看到,加/local参数启动时,直接调用StartService()方法,然后就是和安装windows服务后启动服务一样了。
StartService中调用ServiceLogic.Init()方法进行初始化。代码注释比较少,但已经够我们理解这段代码了。
/// Inits this instance. This method used at startup to initialize
/// all required server components
/// </summary>
public void Init()
{
Access Log Access Log
COM.Handler.LogHandler.Force("Initializing Settings" + COM.Enums.LogCategory.ServiceStart.ToString());
Console.WriteLine(@"Welcome to indeXus.Net Shared Cache");
Console.WriteLine();
Console.WriteLine(COM.Handler.Config.DisplayAppSettings());
COM.Handler.LogHandler.Info(COM.Handler.Config.DisplayAppSettings());
// needs to be instantiated before TCP, it needs an instance of CachExpire
cacheExpireInstance = new CacheExpire();
// TCP needs an instance of CacheExpire
tcpInstance = new TcpServer(cacheExpireInstance);
COM.Handler.LogHandler.Force("Init and Start Thread Tcp");
COM.Handler.LogHandler.Force("Init and Start Thread CacheExpire");
// Init all extenders
// an extender is a class which initializes its own logic around
// specific issue within its own thread;
///////////////////////////////////////////////////////////////////
this.workerTcp = new Thread(this.tcpInstance.Init);
this.workerTcp.Name = "TCP Handler";
this.workerTcp.IsBackground = true;
this.workerTcp.Priority = ThreadPriority.Normal;
///////////////////////////////////////////////////////////////////
this.workerCacheExpire = new Thread(this.cacheExpireInstance.Init);
this.workerCacheExpire.Name = "Cache Expire Handler";
this.workerCacheExpire.IsBackground = true;
this.workerCacheExpire.Priority = ThreadPriority.Lowest;
///////////////////////////////////////////////////////////////////
this.workerCacheExpire.Start();
this.workerTcp.Start();
// enable the search of replicaiton servers
if (this.enableServiceFamilyMode)
{
NetworkDistribution.Init();
}
string msgThreadInfo = Environment.NewLine +
"Main Thread Id: " + Thread.CurrentThread.ManagedThreadId.ToString() + Environment.NewLine +
"this.workerTcp: " + this.workerTcp.ManagedThreadId.ToString() + Environment.NewLine +
/*"this.workerTimer: " + this.workerTimer.ManagedThreadId.ToString() + Environment.NewLine +*/
"this.workerCacheExpire: " + this.workerCacheExpire.ManagedThreadId.ToString();
Console.WriteLine(msgThreadInfo + Environment.NewLine);
Console.WriteLine("+ + + + + + + + + + + + + + + + + + + + + + + + + + + + ");
Console.WriteLine("server is ready to receive data.");
COM.Handler.LogHandler.Force("IndeXus.Net Service Started " + COM.Enums.LogCategory.ServiceStart.ToString());
}
这里启动2个Thread,一个负责执行CacheExpire.Init()方法,负责定时轮查缓Cache中设置有过期策略的对象,如果有到期的,就从Cache中清除。另一个Thread负责监听TCP端口,然后每有一个新的客户端连接过来,又启动一个新的线程处理。
接下来转到MergeSystem.Indexus.WinService.TcpServer.Init()方法:
{
IPEndPoint endpoint = COM.Handler.Network.GetServerAnyIPEndPoint(this.cacheIpPort);
serverSocket = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(endpoint);
serverSocket.Listen((int)SocketOptionName.MaxConnections);
// setup listener issues
acceptThread = new Thread(AcceptConnections);
acceptThread.IsBackground = true;
acceptThread.Priority = ThreadPriority.Normal;
acceptThread.Start();
}
这里启动一个新线程监听TCP 48888(默认值)端口,跟到AcceptConnections方法:
{
while (true)
{
// Accept a connection
Socket socket = serverSocket.Accept();
ConnectionInfo connection = new ConnectionInfo();
connection.Socket = socket;
// Modified:06-01-2008 Merge System GmbH, rschuetz : for more information checkout the following link> http://netrsc.blogspot.com/2007/02/another-extract-from-scalenet-threading.html
ThreadPool.QueueUserWorkItem(this.ProcessConnection, connection);
// Store the socket in the open connections
lock (this.connections)
{
this.connections.Add(connection);
}
}
}
这个比较简单,只是在一个死循环中等待客户端连接,等到后要线程池中执行ProcessConnection方法来处理,此线程继续等待下一个请求。跟到ProcessConnection方法:
{
ConnectionInfo connection = (ConnectionInfo)stats;
try
{
// read data from Socket and convert it to an IndeXusMessage
COM.IndexusMessage msg = new COM.Handler.NetworkMessage().ProcessNetworkMessage(connection.Socket);
if (msg != null)
{
this.ProcessMessage(msg, connection);
}
else
{
Console.WriteLine("Error appears due processing network message!");
COM.Handler.LogHandler.Error("Error appears due processing network message!");
}
}
catch (OutOfMemoryException ex)
{
}
catch (Exception ex)
{
}
finally
{
connection.Socket.Close();
lock (this.connections)
this.connections.Remove(connection);
}
}
这里只调用了COM.Handler.NetworkMessage().ProcessNetworkMessage()方法将客户端发过来的内容还原为IndexusMessage 对象,然后交给ProcessMessage()方法处理:
{
// check status first [Request || Response]
switch (msg.Status)
{
case COM.IndexusMessage.StatusValue.Request:
{
request case request case
}
case COM.IndexusMessage.StatusValue.Response:
{
}
}
}
这里分类对消息进行处理,如添加到缓存或移除等。下面仔细看下Add分支:
{
Add Case Add Case
}
主要完成了4个功能:1.将数据保存到LocalCache中;2.如果要缓存的对象设置有过期时间,则在expire中保存一份存根;3.如果配置有复制服务器,则分发到各兄弟节点;4.如果缓存对象超出了最大值,则使用配置的策略靖仓。LocalCache是MergeSystem.Indexus.WinServiceCommon.Cache类型的静态成员,expire是WinServiceCommon.CacheExpire类型的静态成员。
分析到这里,ShartCache的大概思路已经很清晰了。
ShartCache的核心是MergeSystem.Indexus.WinServiceCommon.Cache和MergeSystem.Indexus.WinServiceCommon.CacheExpire这二个类。WinServiceCommon.Cache中使用一个字典对象readonly Dictionary<string, byte[]> dict;来存储需要缓存的数据,因为要缓存的数据都已经序列化通过TCP传输过来,这里就直接保存byte[]类型的了。WinServiceCommon.CacheExpire类中也有一个字典对象private static Dictionary<string, DateTime> expireTable = null;所有设置有过期时间的缓存对象,都在这里有个存根,过期的缓存有WinServiceCommon.CacheExpire负责清除。
来源:wuchang.cnblogs.com