
文章出處
前言
在互聯網時代,分布式應用、系統變得越來越多,我們在使用 .Net 技術構建分布式系統的時候,需要使用到一些組件或者是助手庫來幫助我們提高生產力以及應用程序解耦,但是縱觀.Net圈,能夠符合要求的這樣的組件并不是很多,并且沒有一個通用的抽象組件能夠將這些接口集成起來,今天就為大家介紹一款開源的組件庫 Foundatio,他們同樣出自于Exceptionless團隊之手,下面就來看看吧。
目錄
緩存
隊列
鎖
消息
工作任務
文件存儲
度量
日志
Foundatio 介紹
GitHub : https://github.com/exceptionless/Foundatio
Foundatio 是一個插件式的,松耦合的一套構建分布式應用的程序庫,出自于Exceptionless團隊。
Foundatio 同時支持 .NET Framework 4.6 和 .NET Core。
通過 Foundatio 我可以獲得哪些幫助呢?
NServiceBus了,很多時候我們僅僅需要的是一個可以在本地或者云上運行的簡單的消息總線。內存文件存儲、文件夾文件存儲,Azure文件存儲,AWS S3文件存儲。Foundatio 主要包含以下模塊:
這些組件都以NuGet包的形式提供出來供我們很方便的使用,
下面依次來看看每一個組件的用途和使用方法吧。
Getting Started
緩存
緩存是一種空間換時間的技術,你可以通過緩存來快速的獲取一些數據。
Foundatio Cache 提供了一致的接口
ICacheClient 來很容易的存儲或者讀取緩存數據,并且提供了4中不同的緩存客戶端的實現。他們分別是:1、
InMemoryCacheClient:內存緩存的實現,這種緩存的生命周期為當前進程, 有一個MaxItems屬性,可以設置最多緩存多少條數據。2、
HybridCacheClient:InMemoryCacheClient 具有相同的實現,但是此接口提供、IMessageBus 可以用來跨線程之間的同步。3、
RedisCacheClient:一個 Redis 客戶端的實現。4、
RedisHybridCacheClient:一個RedisCacheClient 、InMemoryCacheClient 的混合實現,通過RedisMessageBus來保持內存緩存跨線程之間的同步。注意:如果本地緩存的項已經存在,在調用Redis進行序列化保存的時候可能會有性能問題。
5、
ScopedCacheClient:傳入ICacheClient和scope,scope 可以設置一個字符串,來制定一個緩存鍵前綴,這樣可以很方便的進行批量存儲和刪除。例子:
using Foundatio.Caching;
ICacheClient cache = new InMemoryCacheClient();
await cache.SetAsync("test", 1);
var value = await cache.GetAsync<int>("test");隊列
提供了一個先進,先出的消息管道,Foundatio 提供了一個
IQueue接口,并且擁有 4 種不同的隊列實現。1、
InMemoryQueue:一個內存隊列實現,隊列的生命周期為當前進程。2、
RedisQueue:一個 Redis 隊列實現。3、
AzureServiceBusQueue:一個基于Azure的服務消息隊列實現。4、
AzureStorageQueue:一個基于Azure的存儲隊列實現。例子:
using Foundatio.Queues;
IQueue<SimpleWorkItem> queue = new InMemoryQueue<SimpleWorkItem>();
await queue.EnqueueAsync(new SimpleWorkItem {
Data = "Hello"
});
var workItem = await queue.DequeueAsync();鎖
鎖主要是確保無論在什么時候資源只被消費一次,Foundatio 提供了一個
ILockProvider接口,并且有兩種不同的鎖機制的實現。1、
CacheLockProvider:一個緩存鎖實現進程間通訊。2、
ThrottlingLockProvider:只允許一定數量的請求進入ILockProvider的實現。你可以使用這個api調用外部服務,它將通過這個節氣門鎖來限制所有的請求。這里使用了Throttle這個單詞,中文意思是節氣門。為了方便理解給大家科普一下:在汽車的汽油機系統中,節氣門是一個很重要的組件,是用來控制氣體進入引擎的一套可控的閥門。
流程大概就是 空氣-->節氣門-->氣缸,相當于是汽車發動機的咽喉,車子加速是否靈活,與節氣門的清潔是很有關系的。所以此處用了Throttle這個單詞,非常的形象。
需要注意的時候,所有的鎖都是基于
ICacheClient的,所以要確保你代碼中的鎖是否跨機器的。例子:
using Foundatio.Lock;
using Foundatio.Messaging;
ILockProvider locker = new CacheLockProvider(new InMemoryCacheClient(), new InMemoryMessageBus());
await locker.AcquireAsync("test");
// ...
ILockProvider locker = new ThrottlingLockProvider(new InMemoryCacheClient(), 1, TimeSpan.FromMinutes(1));
ILock locks = await locker.AcquireAsync("test");
// ...消息
允許通過你的應用程序發布訂閱消息。Foundatio 提供了一個
IMessageBus接口,并且有4 種不同的實現。1、
InMemoryMessageBus:一個內存消息總線實現。這個消息總線的生命周期為當前進程。2、
RedisMessageBus:一個 Redis 消息總線實現。3、
RabbitMQMessageBus:一個 RabbitMQ 消息總線實現。4、
AzureServiceBusMessageBus:一個Azure Service消息總線實現。例子
using Foundatio.Messaging;
public class Program
{
public static void Main(string[] args) {
MessageBusTest();
Console.ReadKey();
}
public static async void MessageBusTest() {
IMessageBus messageBus = new InMemoryMessageBus();
messageBus.Subscribe<SimpleMessageA>(msg => {
Console.WriteLine(msg.Data);
});
await messageBus.PublishAsync(new SimpleMessageA { Data = "Hello" });
}
public class SimpleMessageA
{
public string Data { get; set; }
}
}工作任務
允許你運行一個長時間的任務,并且不用擔心會被終止。Foundatio提供了一下不同的方法來定義一個Job。
1、
Jobs:提供了一、IJob 接口,和一個默認的基類JobBase。直接上代碼吧:using Foundatio.Jobs;
public class HelloWorldJob : JobBase {
public int RunCount { get; set; }
protected override Task<JobResult> RunInternalAsync(JobRunContext context) {
RunCount++;
return Task.FromResult(JobResult.Success);
}
}
var job = new HelloWorldJob();
await job.RunAsync(); // job.RunCount = 1;
await job.RunContinuousAsync(iterationLimit: 2); // job.RunCount = 3;
await job.RunContinuousAsync(cancellationToken: new CancellationTokenSource(TimeSpan.FromMilliseconds(10)).Token); // job.RunCount > 10;2、
Queue Processor Jobs:和上面的Jobs差不多,只是這個是基于隊列的。using Foundatio.Jobs;
public class HelloWorldQueueJob : QueueJobBase<HelloWorldQueueItem> {
public int RunCount { get; set; }
public HelloWorldQueueJob(IQueue<HelloWorldQueueItem> queue) : base(queue) {}
protected override Task<JobResult> ProcessQueueEntryAsync(QueueEntryContext<HelloWorldQueueItem> context) {
RunCount++;
return Task.FromResult(JobResult.Success);
}
}
public class HelloWorldQueueItem {
public string Message { get; set; }
}
// Register the queue for HelloWorldQueueItem.
container.RegisterSingleton<IQueue<HelloWorldQueueItem>>(() => new InMemoryQueue<HelloWorldQueueItem>());
// To trigger the job we need to queue the HelloWorldWorkItem message.
// This assumes that we injected an instance of IQueue<HelloWorldWorkItem> queue
var job = new HelloWorldQueueJob();
await job.RunAsync(); // job.RunCount = 0; The RunCount wasn't incremented because we didn't enqueue any data.
await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });
await job.RunAsync(); // job.RunCount = 1;
await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });
await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });
await job.RunUntilEmptyAsync(); // job.RunCount = 3;3、
Work Item Jobs:這種類型的Job適合于那些不經常發生,但是應該在一個Job(例如:刪除一個實體,有很多子級)。using System.Threading.Tasks;
using Foundatio.Jobs;
public class HelloWorldWorkItemHandler : WorkItemHandlerBase
{
public override async Task HandleItemAsync(WorkItemContext ctx) {
var workItem = ctx.GetData<HelloWorldWorkItem>();
// We can report the progress over the message bus easily.
// To recieve these messages just inject IMessageSubscriber
// and Subscribe to messages of type WorkItemStatus
await ctx.ReportProgressAsync(0, "Starting Hello World Job");
await Task.Delay(TimeSpan.FromSeconds(2.5));
await ctx.ReportProgressAsync(50, String.Format("Reading value"));
await Task.Delay(TimeSpan.FromSeconds(.5));
await ctx.ReportProgressAsync(70, String.Format("Reading value."));
await Task.Delay(TimeSpan.FromSeconds(.5));
await ctx.ReportProgressAsync(90, String.Format("Reading value.."));
await Task.Delay(TimeSpan.FromSeconds(.5));
await ctx.ReportProgressAsync(100, workItem.Message);
}
}
public class HelloWorldWorkItem
{
public string Message { get; set; }
}
// Register the shared job.
var handlers = new WorkItemHandlers();
handlers.Register<HelloWorldWorkItem, HelloWorldWorkItemHandler>();
// Register the handlers with dependency injection.
container.RegisterSingleton(handlers);
// Register the queue for WorkItemData.
container.RegisterSingleton<IQueue<WorkItemData>>(() => new InMemoryQueue<WorkItemData>());
// The job runner will automatically look for and run all registered WorkItemHandlers.
new JobRunner(container.GetInstance<WorkItemJob>(), instanceCount: 2).RunInBackground();
await queue.EnqueueAsync(new HelloWorldWorkItem { Message = "Hello World" });文件存儲
Foundatio File Storage 提供了一致的接、
IFileStorage 來很容易的存儲或者讀取文件,并且提供了4中不同的文件存儲的實現。他們分別是:1、
InMemoryFileStorage:基于內存的文件存儲,生命周期為當前進程。2、
FolderFileStorage:文件夾存儲,存儲到硬盤中。3、
AzureFileStorage:Azure Blob 存儲的實現。4、
S3Storage:AWS S3 存儲的實現。建議在服務中注入
IFileStorage接口的時候,使用單例方式注入。例子:
using Foundatio.Storage;
IFileStorage storage = new InMemoryFileStorage();
await storage.SaveFileAsync("test.txt", "test");
string content = await storage.GetFileContentsAsync("test.txt")度量
關于Metrics的概念,可以參考 這篇博文。
提供了一個
IMetricsClient 接口,并且有 4 中不同的實現:1、
InMemoryMetricsClient:內存 metrics 的實現。2、
RedisMetricsClient:Redis metrics 的實現。3、
StatsDMetricsClient:statsd metrics 的實現。4、
MetricsNETClient:Metrics.NET 的實現。建議在服務中注入
IMetricsClient接口的時候,使用單例方式注入。例子:
await metrics.CounterAsync("c1");
await metrics.GaugeAsync("g1", 2.534);
await metrics.TimerAsync("t1", 50788);日志
提供了一個流暢型的日志 api, 可用于在應用程序記錄日志消息。并且可以在不需要改變應用程序代碼的情況下,切換各個日志框架。
例子:
ILoggerFactory loggerFactory = new LoggerFactory();
ILogger log = loggerFactory.CreateLogger("Program");
log.Info("Application starting up"); // OR
log.Info().Message("Application starting up").Write();
log.Error(ex, "Writing a captured exception out to the log."); // Or
log.Error().Exception(ex).Message("Writing a captured exception out to the log.").Write();示例程序源碼
示例程序GitHub:
https://github.com/exceptionless/Foundatio.Samples
總結
感謝 Exceptionless 團隊給我們提供了這么簡單易用的 Foundatio 框架,還在等什么,快在你的項目中用起來吧。
如果您覺得本文對您有幫助,想讓更多人了解Exceptionless,感謝您幫忙點的【推薦】。
如果您對 Exceptionless 感興趣或者是想學習 Exceptionless 的代碼,可以加入群
Exceptionless QQ群:330316486。
本文地址:http://www.cnblogs.com/savorboard/p/exceptionless-foundatio.html
作者博客:Savorboard
歡迎轉載,請在明顯位置給出出處及鏈接






