在CodeProject上,使用Redis作为分布式缓存,存储大量的信息,比如文章、论坛消息,并且从缓存而不是数据库中检索这些项目。Redis允许存储和检索完整的文档,而不是为每个请求查询SQL以获取各个部分并组合格式化文档。在网站上这是可能的,因为大多数信息被读取的频率远高于被写入的频率,而且一些信息,比如浏览次数,可以稍微过时一些。
虽然在生产环境中在Linux服务器上运行Redis,但在开发环境中,在Windows 7桌面上运行Microsoft版本的Redis。问题是Redis不是设计为作为Windows服务运行的。这意味着必须有人登录并运行Redis可执行文件。当Chris是唯一登录服务器的人时,这没问题,但上周不得不连接以安装搜索服务器的副本用于开发目的。不用说,这使Chris注销了,并且杀死了Redis服务器。在会话下重新启动了它。
在机器上,正在修复一个微妙的缓存错误,当开始测试时,代码表现得像是与Redis服务器的连接失败。由于正在更改的代码与检测与Redis连接问题有关,在意识到Chris已经远程登录到服务器,杀死了会话和Redis服务器之前,大约转了半个小时的轮子。
Chris和尝试了许多推荐的方法来将Redis作为Windows服务运行,但没有成功。由于编写了几个Windows服务来支持各种CodeProject进程,决定编写一个实用程序,允许将exe作为Windows服务安装和运行。这个实用程序叫做Exe2Srvc。
Exe2Srv是一个可以作为控制台应用程序运行或作为Windows服务安装的程序。这个应用程序读取来自它的.config文件的可执行文件的路径和命令行参数,然后在新进程中启动可执行文件。
使用可执行文件的最简单方法是将binfiles下载的文件或从编译源的bin/Release复制到包含希望作为服务运行的可执行文件的目录中。
编辑Exe2Srvc.exe.config中的"Cmd"和"CmdArgs"值,以包含可执行文件的完整路径和所需的命令行参数。
从'以管理员身份运行'命令shell运行Install.bat文件。
使用服务管理器:
对于测试,从Nuget下载了Redis,并将文件从解决方案目录下的/packages/Redis-64.2.6.12.1/tools复制到C:/Redis。然后将Exe2Srvc\bin\Release中的文件复制到同一个目录。
Exe2Srvc.exe.config文件包含:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<appSettings>
<!-- set Cmd to the executable file name. -->
<!-- set CmdArg to any command arguments required. -->
<add key="Cmd" value="c:\Redis\redis-server.exe" />
<add key="CmdArgs" value="c:\Redis\redis.conf --port 6379" />
</appSettings>
</configuration>
如果可执行文件的路径包含空格,则需要用引号括起来。这可以通过将双引号字符串用单引号括起来来实现,如下所示。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<appSettings>
<!-- set Cmd to the executable file name. -->
<!-- set CmdArg to any command arguments required. -->
<add key="Cmd" value='"c:Program Files\Redis\redis-server.exe"' />
<add key="CmdArgs" value="c:\Redis\redis.conf --port 6379" />
</appSettings>
</configuration>
Install.bat文件,必须以管理员身份运行,使用SC命令安装服务。
sc create Redis binpath= "c:\Redis\Exe2Srvc.exe"
然后使用服务管理器配置服务并启动它。
双击Redis服务以打开属性编辑器并选择恢复选项卡。将选项设置为在错误时重新启动服务,如下所示。
选择常规选项卡。
Redis现在已安装并作为Windows服务运行。使用redis-cli.exe测试连接。
创建一个可以作为Windows服务运行的控制台应用程序,使用了Steve Smith向展示的技术,并基于Einar Egilsson的文章"Run Windows Service as a console program"。基本上,创建一个控制台应用程序,并将Program类更改为派生自ServiceBase。在Main中,使用Environment.UserInteractive属性来确定程序是从命令行运行,还是作为服务运行。
所需的命令和命令行参数从LoadConfiguration方法中读取。
/// <summary>
/// Loads the configuration parameters from the application config file
/// </summary>
private void LoadConfiguration {
// Load the executable filename and command arguements from config file.
_cmd = ConfigurationManager.AppSettings["Cmd"];
_cmdArgs = ConfigurationManager.AppSettings["CmdArgs"];
if (string.IsNullOrWhiteSpace(_cmd))
throw new Exception("The appsetting 'Cmd' was not defined in the config file.");
}
这从Main调用,当作为控制台应用程序启动时,或由服务基础结构作为服务运行时调用。OnStart在下面显示的方式中运行可执行文件。
/// <summary>
/// When implemented in a derived class, executes when a Start command is sent to the
/// service by the Service Control Manager (SCM) or when the operating system starts
/// (for a service that starts automatically).
/// Specifies actions to take when the service starts.
/// </summary>
/// <param name="args">
/// Data passed by the start command.
/// </param>
protected override void OnStart(string[] args) {
if (Environment.UserInteractive) {
string message = String.Format("Starting {0} at {1}.", _serviceName, DateTime.Now);
Console.WriteLine(message);
}
// loading the configuration file info here allows the service to be stopped,
// the configuration modified, and the service restarted.
LoadConfiguration();
// Start the executable.
ProcessStartInfo procInfo = new ProcessStartInfo(_cmd);
procInfo.UseShellExecute = false;
if (!string.IsNullOrWhiteSpace(_cmdArgs))
procInfo.Arguments = _cmdArgs;
_process = Process.Start(procInfo);
}
当服务停止时,调用OnStop方法。这会杀死进程,等待它终止,并处理进程。确保等待进程终止,否则将导致服务不正确地停止,难以移除和修复。
/// <summary>
/// When implemented in a derived class, executes when a Stop command is sent to the service
/// by the Service Control Manager (SCM). Specifies actions to take when a service stops running.
/// </summary>
/// <remarks>
/// Stops the background tasks.
/// </remarks>
protected override void OnStop() {
if (Environment.UserInteractive) {
string message = String.Format("Stopping {0} at {1}.", _serviceName, DateTime.Now);
Console.WriteLine(message);
}
// Kill the process if
if (_process != null) {
_process.Kill();
_process.WaitForExit();
_process.Dispose();
_process = null;
}
}
已尽力使这个尽可能简单和灵活,但它只满足了最初的要求,即能够将Windows版本的Redis作为Windows服务器运行。如果有额外的要求,请随时修改代码以满足需求。