废话少说, 一杯代码为敬.
进入代码之前, 我先来演示下代码结构. 这个结构对应我之前的代码实践. 内存队列, 爬虫在我的博客内都能找到博客对应.
演示结构图
今天我们只说 zipkin4Net 的实践. 为了测试查看 zipkin 是否能够汇集不同的站点, 我特意建立了两个站点 Demo.ZipKinweb 和 Demo.ZipKinWeb2. 类似下图:
image.png
为了能真实落库, 我创建了 FanQuick.Repository, 用于提供 mongodb 存储帮助. IRepository 泛型接口声明如下
- namespace FanQuick.Repository
- {
- public interface IRepository<TDocument> where TDocument:EntityBase
- {
- IQueryable<TDocument> Queryable { get; }
- bool Any(Expression<Func<TDocument, bool>> filter);
- /// <summary>
- /// 删除
- /// </summary>
- /// <param name="filter"></param>
- /// <returns></returns>
- bool Delete(Expression<Func<TDocument, bool>> filter);
- /// <summary>
- /// 查询
- /// </summary>
- /// <param name="filter"></param>
- /// <returns></returns>
- IEnumerable<TDocument> Find(Expression<Func<TDocument, bool>> filter);
- /// <summary>
- /// 新增
- /// </summary>
- /// <param name="document"></param>
- void Insert(TDocument document);
- /// <summary>
- /// 批量插入
- /// </summary>
- /// <param name="documents"></param>
- void Insert(IEnumerable<TDocument> documents);
- /// <summary>
- /// 统计.
- /// </summary>
- /// <param name="filter"></param>
- /// <returns></returns>
- long Count(Expression<Func<TDocument, bool>> filter);
- TDocument FindOneAndDelete(Expression<Func<TDocument, bool>> filter);
- TDocument FindOneAndUpdate(FilterDefinition<TDocument> filter, UpdateDefinition<TDocument> update);
- }
- }
为了两个站点能够复用调用 zipkin4net 的通知, 我将代码抽离出来放到了 Demo.ZipkinCommon.
可复用的抽象类 CommonStartUp, 代码如下: 重点关注下调用 zipkin4net 的代码. 并将抽象 Run 方法暴漏给了子类, 需要子类实现. 要特别注意, appsettings.json 需要设置 applicationName, 不然发送到 zipkin 就是未命名服务, 这就不能区分站点了!
- namespace Demo.ZipkinCommon
- {
- public abstract class CommonStartup
- {
- // This method gets called by the runtime. Use this method to add services to the container.
- // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
- public abstract void ConfigureServices(IServiceCollection services);
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
- {
- var config = ConfigureSettings.CreateConfiguration();
- var applicationName = config["applicationName"];
- //if (env.IsDevelopment())
- //{
- // app.UseDeveloperExceptionPage();
- //}
- //else
- //{
- // app.UseExceptionHandler("/Home/Error");
- // app.UseHsts();
- //}
- var lifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
- lifetime.ApplicationStarted.Register(() =>
- {
- TraceManager.SamplingRate = 1.0f;
- var logger = new TracingLogger(loggerFactory, "zipkin4net");
- var httpSender = new HttpZipkinSender("http://weixinhe.cn:9411", "application/json");
- var tracer = new ZipkinTracer(httpSender, new JSONSpanSerializer());
- TraceManager.RegisterTracer(tracer);
- TraceManager.Start(logger);
- });
- lifetime.ApplicationStopped.Register(() => TraceManager.Stop());
- app.UseTracing(applicationName);
- Run(app, config);
- }
- protected abstract void Run(IApplicationBuilder app, IConfiguration configuration);
- }
- }
读取配置类, 也独立了出来, 可支持读取 appsettings.json, 每个站点需要把 appsettings.json 设置允许复制, 不然会找不到文件!!
- namespace Demo.ZipkinCommon
- {
- public class ConfigureSettings
- {
- public static IConfiguration CreateConfiguration()
- {
- var builder = new ConfigurationBuilder()
- .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
- .AddEnvironmentVariables();
- return builder.Build();
- }
- }
- }
公用部分完成了. 我们看看站点 Demo.ZipKinWeb 代码. Startup 继承抽象类 CommonStartup, 并利用. netCore 内置依赖注入, 将 Service 和仓储注入进来. 由于不支持直接注入泛型, 但支持 type 类型的注入, 间接也解决了泛型注入问题. 关于依赖注入的讲解, 你可以参考上篇文中依赖注入部分, 加深理解.
- namespace Demo.ZipKinWeb
- {
- public class Startup : CommonStartup
- {
- public Startup(IConfiguration configuration)
- {
- Configuration = configuration;
- }
- public IConfiguration Configuration { get; }
- public override void ConfigureServices(IServiceCollection services)
- {
- services.Configure<CookiePolicyOptions>(options =>
- {
- // This lambda determines whether user consent for non-essential cookies is needed for a given request.
- options.CheckConsentNeeded = context => true;
- options.MinimumSameSitePolicy = SameSiteMode.None;
- });
- services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));
- services.AddScoped<IUserService, UserService>();
- services.AddScoped<IAddressService, AddressService>();
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
- }
- protected override void Run(IApplicationBuilder app, IConfiguration configuration)
- {
- app.UseHttpsRedirection();
- app.UseStaticFiles();
- app.UseCookiePolicy();
- app.UseMvc(routes =>
- {
- routes.MapRoute(
- name: "default",
- template: "{controller=Home}/{action=Index}/{id?}");
- });
- }
- }
- }
为了实现聚合两个站点的效果, 在 Add 的方法内, 特意调用一下另外个站点的 get
- [HttpPost]
- public IActionResult Add([FromBody]User user)
- {
- _userService.AddUser(user);
- // 模拟调用其他站点请求.
- var client = new RestClient($"{ConfigEx.WebSite}");
- var request = new RestRequest($"/user/get", Method.POST);
- request.AddParameter("id", user.Id); // adds to POST or URL querystring based on Method
- IRestResponse response = client.Execute(request);
- var content = response.Content;
- // return Json(new { data = content });
- return Content(content+_addressService.Test());
- }
建好必要的 Controller 和 Action 后, 将两个站点都设为已启动. 就可以查看效果了.
postman 是个测试接口的好工具, 点击 Send.
postman 接口测试
打开我们的 zipkin 服务器链接, 在 WebUI 上, 可以看到两条请求数据. 这是正确的, 一条是 Add, 里面又调了另外一个站点的 get, 也能看到消耗的时间.
监测数据
点击去查看详情, 我们能看到更多数据.
请求详情
然后继续点击 菜单中的 Dependencies, 确发现是空值, 按道理来讲, 请求了两个站点, 又访问了数据库. 怎么会是空值呢???
依赖
这个时候, 我只能又求助 bing 了.
zipkin Dependencies no data
果然网友是万能的. elasticsearch 存储, zipkin 依赖没有数据 https://github.com/openzipkin/zipkin/issues/2016
里面有位外国同仁提到了
当你用你 elasticsearch 或 Cassandra 的时候, 需要执行 zipkin-dependencies
(you need to run https://github.com/openzipkin/zipkin-dependencies when using elasticsearch or Cassandra)
来源: https://www.cnblogs.com/fancunwei/p/9649192.html