
如今,大多数信息系统都是具有复杂体系结构和大量相互依赖关系的复杂解决方案。 在此类系统的运行过程中,在峰值负载时,某些模块可能会出现故障,或者可能无法正常工作。 在这种情况下,系统将不再稳定,并且可能会停止正确处理所有传入请求。 为了确保系统的稳定运行,可以实施各种策略。
在某些情况下(如果允许),将系统翻译成所谓的。 “安全模式”。 在这种模式下,系统可以处理大量呼叫,但查询处理结果的准确性略有下降。 在其他情况下,扩展计算资源和增加负责处理传入请求的单个系统模块的数量可能会有所帮助。 在这种情况下,最重要的任务是
确定系统的状态 ,取决于
该状态,必须已经采取一种或另一种措施来稳定其工作。
在我的项目中,很长时间以来,我一直以各种方式解决类似的问题。 自从我上大学以来,我就有一个用.NET 4.0编写的小项目,从那时起,我不时地为实际项目编写一小段代码。 我长期以来就计划重构该项目,将其清理并以单独的微型框架的形式进行安排,从而使我们能够精美而简约地解决监视系统状态的问题。 在度过了几个晚上和几天的休假之后,我将这段代码整理好并发布到了
GitHub上 。 此外,我建议更详细地考虑在此项目中实现什么以及如何实现。
为了确定需要更改系统的运行模式,建议使用一种使用虚拟“传感器”和“观察者”的方法。

▌实体和定义
要使用的基本实体:
- 传感器 -负责检查系统指标之一的状态;
- 观察者 -询问一个或多个传感器。 根据传感器的当前读数更改其状态;
- 状态计算器 -根据指标日志计算当前状态。
- 状态日志 -每个传感器的一组指示轮询时间的指示器。
对于每个抽象,都有一个基本的实现以及用于简单方便扩展的机制。 让我们更详细地考虑它们。
感应器
基本的
IProbe界面。 实现IProbe的类可根据要求提供它们观察到的系统参数或特定模块/服务的值。
public interface IProbe { string Name { get; } Task<ProbeResult> Check(); }
作为
Check方法的结果,该IProbe实例返回一个ProbeResult结构
public struct ProbeResult { public string ProbeName { get; set; } public DateTime Time { get; set; } public bool Success { get; set; } public string Data { get; set; } public Exception Exception { get; set; } public override string ToString() => $"{Time}: {Success}"; }
其中“成功”字段从传感器的角度确定参数是否已成功测试,并且“数据”和“异常”字段可以存储其他信息,以防需要调试或记录日志。
观察者
ISpectator的基本接口。 它监视系统,并在更改系统状态时生成事件,以通知订阅这些事件的所有模块。 它使用实现IStateEvaluator接口的类的实例来计算当前状态。
public interface ISpectator<TState> where TState : struct, IConvertible { event EventHandler<StateEventArgs<TState>> StateChanged; event EventHandler<HealthCheckEventArgs> HealthChecked; TState State { get; } TimeSpan Uptime { get; } string Name { get; } void AddProbe(IProbe probe); void CheckHealth(); }
在每个传感器轮询期间,观察者引发StateChanged事件,并将类型
StateEventArgs的对象传递给该事件的订阅者,其中包含有关系统当前状态的信息。
状态计算器
基本的
IEvaluator接口。 根据传感器状态日志计算系统的当前状态。
public interface IStateEvaluator<TState> { TState Evaluate( TState currentState, DateTime stateChangedLastTime, IReadOnlyCollection<JournalRecord> journal); }
状态日志
JournalRecord结构实例的集合。 JournalRecord实例存储有关由观察者发起轮询时所轮询的所有传感器的信息。
public struct JournalRecord { public JournalRecord(DateTime time, IEnumerable<ProbeResult> values) { Time = time; Values = values.ToImmutableList(); } public DateTime Time { get; set; } public IReadOnlyCollection<ProbeResult> Values { get; set; } public override string ToString() => $"{Time}: [{string.Join(",", Values)}]"; }
▌如何运作
计算系统状态的过程可以描述如下:嵌入在系统中的每个传感器都可以确定观察到的系统/模块/服务的参数之一。 例如,它可以确定对API的外部活动请求的数量,使用的RAM数量,高速缓存中的条目数等。
每个传感器可以分配给一个或几个观察者。 每个观察者可以使用一个或多个传感器。 观察者必须实现ISpectator接口,并在状态改变或传感器轮询时生成事件。
在下一次检查系统状态时,观察者将轮询其所有“传感器”,形成一个数组以写入状态日志。 如果系统状态已更改,则观察者会生成适当的事件。 接收有关更改信息的事件订阅者可以更改系统的操作参数。 同时,可以使用各种类型的“计算机”来确定系统的状态。
同步和异步操作模式
考虑观察者发起“传感器”调查的两种主要情况。
同步模式
系统模块之一对观察者的直接吸引力引起对传感器的调查,然后重新计算系统状态。
在这种情况下,观察者和传感器在同一线程中工作。 系统状态的错误计算是系统内操作的一部分。
该项目已经有了这样一个观察者的基本实现
-SpectatorBase 。
查看代码 public class SpectatorBase<TState> : ISpectator<TState> where TState : struct, IConvertible { private TState _state; private readonly IList<IProbe> _probes; private readonly IStateEvaluator<TState> _stateEvaluator; private readonly List<JournalRecord> _journal; private readonly ReaderWriterLockSlim _journalLock; private readonly ReaderWriterLockSlim _stateLock; private readonly Stopwatch _stopwatch; public event EventHandler<StateEventArgs<TState>> StateChanged; public event EventHandler<HealthCheckEventArgs> HealthChecked; public virtual TState State { get { _stateLock.EnterReadLock(); try { return _state; } finally { _stateLock.ExitReadLock(); } } } public TimeSpan Uptime => _stopwatch.Elapsed; public string Name { get; set; } public IReadOnlyCollection<JournalRecord> Journal { get { _journalLock.EnterReadLock(); try { return _journal; } finally { _journalLock.ExitReadLock(); } } } public DateTime StateChangedDate { get; private set; } public TimeSpan RetentionPeriod { get; private set; } public SpectatorBase(IStateEvaluator<TState> stateEvaluator, TimeSpan retentionPeriod, TState initialState) { RetentionPeriod = retentionPeriod; _state = initialState; StateChangedDate = DateTime.UtcNow; _stateEvaluator = stateEvaluator; _stopwatch = Stopwatch.StartNew(); _probes = new List<IProbe>(); _journal = new List<JournalRecord>(); _journalLock = new ReaderWriterLockSlim(); _stateLock = new ReaderWriterLockSlim(); } public void AddProbe(IProbe probe) => _probes.Add(probe); protected virtual void ChangeState(TState state, IEnumerable<string> failedProbes) { _stateLock.EnterWriteLock(); try { _state = state; } finally { _stateLock.ExitWriteLock(); } StateChangedDate = DateTime.UtcNow; StateChanged?.Invoke(this, new StateEventArgs<TState>(state, StateChangedDate, failedProbes)); } public virtual void CheckHealth() { var results = new Stack<ProbeResult>(); var tasks = _probes .Select(async o => { results.Push(await o.Check().ConfigureAwait(false)); }) .ToArray(); Task.WaitAll(tasks); var now = DateTime.UtcNow; _journalLock.EnterWriteLock(); try {
异步模式
在这种情况下,传感器的询问与系统的过程异步发生,并且可以在单独的线程中执行。 这样的观察者的基本实现也已经是一个项目
AutomatedSpectator 。
查看代码 public class AutomatedSpectator<TState> : SpectatorBase<TState>, IAutomatedSpectator<TState> where TState : struct, IConvertible { public TimeSpan CheckHealthPeriod { get; } private readonly System.Timers.Timer _timer; public AutomatedSpectator( TimeSpan checkHealthPeriod, TimeSpan retentionPeriod, IStateEvaluator<TState> stateEvaluator, TState initialState) : base(stateEvaluator, retentionPeriod, initialState) { CheckHealthPeriod = checkHealthPeriod; _timer = new System.Timers.Timer(CheckHealthPeriod.TotalMilliseconds); _timer.Elapsed += (sender, args) => CheckHealth(); _timer.AutoReset = true; } public void Start() => _timer.Start(); }
▌结论
使用X.Spectator可以亲自帮助我完成多个高负荷项目,从而大大提高了许多服务的稳定性。 当在基于微服务体系结构构建的分布式系统中实施时,提出最好的框架已得到证明。 当使用IoC容器实现传感器的过程并且观察者以单调的形式呈现时,最佳的集成选项是使用控制反转原理,即依赖关系的实现,观察者以单调的形式呈现,其中每个观察者的单个实例可以通过不同类的模块和服务进行访问。
▌链接和有用信息
→
项目资料库→
例子→
NuGet软件包