博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
性能分析
阅读量:6285 次
发布时间:2019-06-22

本文共 4233 字,大约阅读时间需要 14 分钟。

StackExchange.Redis 公开了少量的方法和类型来开启性能分析。由于其异步性和多路复用行为,性能分析是一个有点复杂的话题。

接口

性能分析接口是由这些组成的:IProfiler,ConnectionMultiplexer.RegisterProfiler(IProfiler),ConnectionMultiplexer.BeginProfiling(object), ConnectionMultiplexer.FinishProfiling(object) 还有 IProfiledCommand。

你可以用 ConnectionMultiplexer 的实例来注册一个 IProfiler 接口,注册后它不能被更改。通过调用 BeginProfiling(object)方法开始分析一个给定的上下文(例如:Thread,HttpRequest等等),然后调用 FinishProfiling(object) 方法完成分析;FinishProfiling(object) 方法返回一个 IProfiledCommand 的集合,该集合包含计时信息的所有命令都被发送到Redis;使用给定的上下文参数,通过已配置的 ConnectionMultiplexer 对像来调用 (Begin|Finish)Profiling (也就是BeginProfiling & FinishProfiling) 方法。

在具体的应用中什么样的 "上下文" 对象应该使用。

Available Timings

StackExchange.Redis公共的信息有:

  • 涉及的Redis服务器
  • 对Redis数据库的查询
  • 运行的Redis命令
  • 路由命令的使用标志
  • 命令的初始化创建时间
  • 用了多长时间来排队命令
  • 在排队之后,用了多长时间来发送命令
  • 在命令被发送后,用了多长时间接受来自Redis的响应
  • 在接受响应后,用了多长时间来处理响应
  • 如果命令被发送以回应一个集群 ASK 或 MOVED 的响应
    • 如果这样,那么原始的命令的 TimeSpan 是高精确度的, 如果运行时支持。DateTime 和 DateTime.UtcNow 精确度是一样的。

选择上下文

由于StackExchange.Redis的异步接口,分析需要外部协助来组织相关的命令。开始分析和结束分析都是通过给定的上下文对象来实现的(通过 BeginProfiling(object) & FinishProfiling(object) 方法实现),通过 IProfiler 接口的 GetContext 方法取得上下文对象。

下面是一个从很多不同的线程发出相关命令的示例:

class ToyProfiler : IProfiler{    public ConcurrentDictionary
Contexts = new ConcurrentDictionary
(); public object GetContext() { object ctx; if(!Contexts.TryGetValue(Thread.CurrentThread, out ctx)) ctx = null; return ctx; } } // ... ConnectionMultiplexer conn = /* initialization */; var profiler = new ToyProfiler(); var thisGroupContext = new object(); //注册实现了IProfiler接口的对象 conn.RegisterProfiler(profiler); var threads = new List
(); for (var i = 0; i < 16; i++) { var db = conn.GetDatabase(i); var thread = new Thread( delegate() { var threadTasks = new List
(); for (var j = 0; j < 1000; j++) { var task = db.StringSetAsync("" + j, "" + j); threadTasks.Add(task); } Task.WaitAll(threadTasks.ToArray()); } ); profiler.Contexts[thread] = thisGroupContext; threads.Add(thread); } //分析开始 conn.BeginProfiling(thisGroupContext); threads.ForEach(thread => thread.Start()); threads.ForEach(thread => thread.Join()); //分析结束,并且返回了含定时信息的所有命令集合 IEnumerable
timings = conn.FinishProfiling(thisGroupContext);

在结束后,timings 包含了16,000个 IProfiledCommand 对象:每一个命令都会被发送到Redis。

替代方案,你可以按照如下做:

ConnectionMultiplexer conn = /* initialization */;var profiler = new ToyProfiler();conn.RegisterProfiler(profiler);var threads = new List
();var perThreadTimings = new ConcurrentDictionary
>(); for (var i = 0; i < 16; i++) { var db = conn.GetDatabase(i); var thread = new Thread( delegate() { var threadTasks = new List
(); conn.BeginProfiling(Thread.CurrentThread); for (var j = 0; j < 1000; j++) { var task = db.StringSetAsync("" + j, "" + j); threadTasks.Add(task); } Task.WaitAll(threadTasks.ToArray()); perThreadTimings[Thread.CurrentThread] = conn.FinishProfiling(Thread.CurrentThread).ToList(); } ); profiler.Contexts[thread] = thread; threads.Add(thread); } threads.ForEach(thread => thread.Start()); threads.ForEach(thread => thread.Join());

perThreadTimings 最终会包含16项1,000个 IProfilingCommand 记录,以线程作为键来获取perThreadTimings集合中的值来发送它们。

让我们忘记玩具示例,这里展示的是一个在MVC5应用中配置StackExchange.Redis的示例:

首先注册 IProfiler 接口,而不是 ConnectionMultiplexer :

public class RedisProfiler : IProfiler{    const string RequestContextKey = "RequestProfilingContext"; public object GetContext() { var ctx = HttpContext.Current; if (ctx == null) return null; return ctx.Items[RequestContextKey]; } public object CreateContextForCurrentRequest() { var ctx = HttpContext.Current; if (ctx == null) return null; object ret; ctx.Items[RequestContextKey] = ret = new object(); return ret; } }

那么,添加下面的代码到你的Global.asax.cs文件中:

protected void Application_BeginRequest(){    var ctxObj = RedisProfiler.CreateContextForCurrentRequest();    if (ctxObj != null)    {        RedisConnection.BeginProfiling(ctxObj);    }}protected void Application_EndRequest() { var ctxObj = RedisProfiler.GetContext(); if (ctxObj != null) { var timings = RedisConnection.FinishProfiling(ctxObj); // 在这里你可以使用`timings`做你想做的 } }

这些实现会组织所有的Redis命令,包括 async/await 并随着http请求初始化它们。

转载于:https://www.cnblogs.com/carldai/p/5497055.html

你可能感兴趣的文章
CSS基础知识(上)
查看>>
PHP中常见的面试题2(附答案)
查看>>
26.Azure备份服务器(下)
查看>>
mybatis学习
查看>>
LCD的接口类型详解
查看>>
Spring Boot Unregistering JMX-exposed beans on shutdown
查看>>
poi 导入导出的api说明(大全)
查看>>
Mono for Android 优势与劣势
查看>>
将图片转成base64字符串并在JSP页面显示的Java代码
查看>>
js 面试题
查看>>
sqoop数据迁移(基于Hadoop和关系数据库服务器之间传送数据)
查看>>
腾讯云下安装 nodejs + 实现 Nginx 反向代理
查看>>
Javascript 中的 Array 操作
查看>>
java中包容易出现的错误及权限问题
查看>>
AngularJS之初级Route【一】(六)
查看>>
服务器硬件问题整理的一点总结
查看>>
SAP S/4HANA Cloud: Revolutionizing the Next Generation of Cloud ERP
查看>>
Mellanox公司计划利用系统芯片提升存储产品速度
查看>>
白帽子守护网络安全,高薪酬成大学生就业首选!
查看>>
ARM想将芯片装进人类大脑 降低能耗是一大挑战
查看>>