十年河东,十年河西,莫欺少年穷
学无止境,精益求精
上一节通过两台windowsServer服务器部署了Redis的哨兵模式,详情参考:两台windowserver服务器配置Redis哨兵集群----一主二从
redis通过主从复制来实现高可用,但是发生故障时需要人工进行主从切换,效率低下。哨兵机制实现了redis主从的自动切换,提高了redis集群的可用性,提高了redis集群的故障转移效率。 我们可以看到哨兵机制是有缺点的:
1.主从服务器的数据要经常进行主从复制,这样造成性能下降。
2.当主服务器宕机后,从服务器切换成主服务器的那段时间,服务是不能用的。
3.为了保证redis的真真的高可用官方推荐使用redis-cluster集群。 一般的项目我们采用redis的哨兵模式架构(推荐采用一主二从三哨兵)就可以满足业务要求了
1、新建控制台应用程序
引用如下:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="CSRedisCore" Version="3.8.803" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.9" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.9" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.1.9" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.11" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.9" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.0.4" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\Common\Common.csproj" /> </ItemGroup> <ItemGroup> <None Update="appsettings.json"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> <None Update="nlog.config"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> </ItemGroup> </Project>View Code
代码如下:
using Common; using CSRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; namespace CSRedisCoreTEST { class Program { static void Main(string[] args) { ConfigurationBuilder builder = new ConfigurationBuilder(); builder.AddJsonFile("appsettings.json", true, true); var ConfigRoot = builder.Build();//根节点 IServiceCollection Services = new ServiceCollection(); Services.AddLogging(log => { log.AddConsole(); log.AddNLog(); log.SetMinimumLevel(LogLevel.Error); }); string sentinelConnectString = ConfigRoot.GetSection("CsRedisConfig:SentinelConnectString").Value; string[] sentinelValues = ConfigRoot.GetSection("CsRedisConfig:Sentinel").Get<string[]>(); // 创建redis哨兵访问类(Redis Sentinel) var csredis = new CSRedis.CSRedisClient(connectionString: sentinelConnectString, sentinels: sentinelValues); // 初始化 RedisHelper RedisHelper.Initialization(csredis); // 将csredis实例注册到管道中 Services.AddSingleton<CSRedis.CSRedisClient>(RedisHelper.Instance); Services.AddScoped<RdsTestService>(); using (ServiceProvider provider = Services.BuildServiceProvider()) { var der = provider.GetService<RdsTestService>(); der.TestSet(); der.TestGet(); } CreateHostBuilder(args).Run(); } public static IHost CreateHostBuilder(string[] args) { var builder = Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.AddHostedService<BeatService>(); }).UseWindowsService(); var host = builder.Build(); return host; } } public class RdsTestService { private readonly CSRedis.CSRedisClient cSRedisClient; public RdsTestService(CSRedis.CSRedisClient cSRedisClient) { this.cSRedisClient = cSRedisClient; } public void TestSet() { this.cSRedisClient.Set("testDF","我是一只小小小奥鸟",TimeSpan.FromMinutes(4)); } public void TestGet() { var result = this.cSRedisClient.Get("testDF"); } } public class BeatService : BackgroundService { private readonly ILogger<BeatService> _logger; public BeatService( ILogger<BeatService> logger) { _logger = logger; } public override Task StartAsync(CancellationToken cancellationToken) { return base.StartAsync(cancellationToken); } /// <summary> /// 每一秒执行一次 /// </summary> /// <param name="stoppingToken"></param> /// <returns></returns> protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { var result = CSRedisHelper.GetInstance().Get("testDF"); Console.WriteLine("BackgroundService通过单例模式获取到的值为:" + result); await Task.Delay(1000, stoppingToken); } } } }View Code
配置文件如下:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "CsRedisConfig": { "SentinelConnectString": "mymaster,defaultDatabase=3,poolsize=1000", "Sentinel": [ "172.27.40.27:26379", "172.27.40.29:26379", "172.27.40.29:26380" ] } }
nlog.config如下
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="Info" internalLogFile="logs/internal-nlog-AspNetCore.txt"> <!-- enable asp.net core layout renderers --> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <!-- the targets to write to --> <targets> <!-- File Target for all log messages with basic details --> <target xsi:type="File" name="allfile" fileName="logs/log-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}" archiveAboveSize="10000" maxArchiveFiles="3"/> <!-- File Target for own log messages with extra web details using some ASP.NET core renderers --> <target xsi:type="File" name="ownFile-web" fileName="logs/nlog-AspNetCore-own-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}|${callsite}" archiveAboveSize="10000" maxArchiveFiles="3" /> <!--Console Target for hosting lifetime messages to improve Docker / Visual Studio startup detection --> <target xsi:type="Console" name="lifetimeConsole" layout="${MicrosoftConsoleLayout}" /> </targets> <!-- rules to map from logger name to target --> <rules> <!--All logs, including from Microsoft--> <logger name="*" minlevel="Trace" writeTo="allfile" /> <!--Output hosting lifetime messages to console target for faster startup detection --> <logger name="Microsoft.Hosting.Lifetime" minlevel="Info" writeTo="lifetimeConsole, ownFile-web" final="true" /> <!--Skip non-critical Microsoft logs and so log only own logs (BlackHole) --> <logger name="Microsoft.*" maxlevel="Info" final="true" /> <logger name="System.Net.Http.*" maxlevel="Info" final="true" /> <logger name="*" minlevel="Trace" writeTo="ownFile-web" /> </rules> </nlog>View Code
2、新建公共类库,用于Csredis单例模式
引用如下:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="CSRedisCore" Version="3.8.803" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.9" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.9" /> </ItemGroup> </Project>
公共类如下:
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json; using System; using CSRedis; namespace Common { public class ConfigCommon { public static IConfiguration Configuration { get; set; } static ConfigCommon() { //#if DEBUG // Configuration = new ConfigurationBuilder() // .Add(new JsonConfigurationSource { Path = "appsettings.Development.json", ReloadOnChange = true }) // .Build(); //#else // Configuration = new ConfigurationBuilder() // .Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true }) // .Build(); //#endif Configuration = new ConfigurationBuilder() .Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true }) .Build(); } public static string GetConfig(string key, string defaultValue = "") { string settingValue = Configuration[key]; return string.IsNullOrEmpty(settingValue) ? defaultValue : settingValue; } } /// <summary> /// 单例模式的实现 /// </summary> public class CSRedisHelper { // 定义一个静态变量来保存类的实例 private static CSRedisClient Instance; // 定义一个标识确保线程同步 private static readonly object locker = new object(); // 定义私有构造函数,使外界不能创建该类实例 private CSRedisHelper() { } /// <summary> /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 /// </summary> /// <returns></returns> public static CSRedisClient GetInstance() { // 当第一个线程运行到这里时,此时会对locker对象 "加锁", // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁 // lock语句运行完之后(即线程运行完之后)会对该对象"解锁" // 双重锁定只需要一句判断就可以了 if (Instance == null) { lock (locker) { // 如果类的实例不存在则创建,否则直接返回 if (Instance == null) { Console.WriteLine(DateTime.Now.ToString("HHmmss") + "开始获取实例"); string sentinelConnectString = ConfigCommon.GetConfig("CsRedisConfig:SentinelConnectString"); string[] sentinelValues = ConfigCommon.Configuration.GetSection("CsRedisConfig:Sentinel").Get<string[]>(); // 创建redis哨兵访问类(Redis Sentinel) Instance = new CSRedis.CSRedisClient(connectionString: sentinelConnectString, sentinels: sentinelValues); // 初始化 RedisHelper RedisHelper.Initialization(Instance); } } } return Instance; } } }View Code
标签:string,NetCore,redis,Redis,CSRedis,new,using,Configuration,public From: https://www.cnblogs.com/chenwolong/p/18230595