实时监控Cat之旅~分布式消息树的实现原理与测试

时间:2021-11-04 12:27:26

大众点评的老吴在InfoQ上讲了Cat之后,有不少同仁开始关注这个实时监控系统,但学习的文章甚少,在GitHub上也是一言代过,给我们这些开发人员留下了N多个疑问,一时间不知道去哪里问,向谁去问了,通常的百度和谷歌也不好使了,不过,好在经理推荐的QQ群帮了忙,认识了一些cat的前辈,经过他们的努力和我们共同的执着,终于把这块难啃的骨头啃动了!

参考代码:https://github.com/chinaboard/PureCat

完成的分布式消息树

实时监控Cat之旅~分布式消息树的实现原理与测试

分布式消息树实现的理论

Cat上下文,它与其它数据上下文,Http上下文,文件上下文的意思是一样的,都是指一种对象的封装,在cat里它的上下文由三个ID组成,ROOT,Parent和Child,他们类似于数据库里的联合主键,在让多个消息进行关联时,需要通过这些键值,我们在跨网络记录日志时,也需要把这三个对象传过去,在目标服务器上进行解析,然后这两个消息就组成了一个消息树了。

CatContext上下文内容

    /// <summary>
    /// cat上下文
    /// </summary>
    public class CatContext
    {
        /// <summary>
        /// 消息根ID
        /// </summary>
        public string CatRootId { get; set; }
        /// <summary>
        /// 上级消息ID
        /// </summary>
        public string CatParentId { get; set; }
        /// <summary>
        /// 当前消息ID
        /// </summary>
        public string CatChildId { get; set; }
        public string ContextName { get; set; }

        public CatContext(string contextName)
        {
            ContextName = contextName ?? Environment.MachineName;
        }
        public CatContext()
            : this(null)
        {

        }

    }

在进行分布式调用时,和java版的一样,用到了LogRemoteCallClient和LogRemoteCallServer这两个方法,前者是消息发起者调用,生成context后,将它序列化传到另外一个节点,这个节点在进行事务处理时会将自己包裹到调用方的事务时在,这也就是分布式消息树的实现原理。

需要注意的地方

在Cat里,有域的概念,即domain,我们在分布式消息树的几台服务器,必须处在同一个域下!

代码这样实现的

A节点核心代码

 /* client1 -> catContext -> client2
             * 
             */
            #region Cat实时监控

            PureCat.PureCat.Initialize();
            var context = PureCat.PureCat.DoTransaction("Do", "Test", func: () =>
           {

               PureCat.PureCat.NewEvent("Do", "Test");
               return PureCat.PureCat.LogRemoteCallClient("zzl");
           });

            var url = "http://localhost:4532/home/index";
            var handler = new HttpClientHandler() { };
            using (var http = new HttpClient(handler))
            {
                http.DefaultRequestHeaders.Add("catContext", Lind.DDD.Utils.SerializeMemoryHelper.SerializeToJson(context));
                var response = http.GetAsync(url).Result;
                var staus = response.IsSuccessStatusCode;
            }

            Console.ReadLine();
            #endregion

对于分布式消息树上下文的Name,我们可以使用Guid码生成,避免冲突!

B节点核心代码

       string reusult = Request.Headers.GetValues("catContext").FirstOrDefault();
            var cat = Lind.DDD.Utils.SerializeMemoryHelper.DeserializeFromJson<PureCat.Context.CatContext>(reusult);
            PureCat.PureCat.DoTransaction("Do", "Add", () =>
            {
                PureCat.PureCat.LogRemoteCallServer(cat);
                PureCat.PureCat.LogEvent("Do", "Add", "0", "hello distribute api123");
                PureCat.PureCat.LogError(new Exception());
            });

本文代码只是大叔的测试DEMO,之后还会对它进行封装与优化,敬请期待!

感谢您的阅读!