伴鱼技术团队

Technology changes the world

伴鱼开放平台 上线了! 源于实践的解决方案,助力企业成就未来!

O(1) LFU

本文源自 2010 年的一篇论文 An O(1) algorithm for implementing the LFU cache eviction scheme

简介

缓存置换算法 (Cache Eviction Algorithm) 在操作系统、数据库以及其它系统中被广泛用于缓存置换模块,当缓存空间不足时,它利用局部性原理 (Principle of Locality) 预测未来数据的使用模式,将最不可能被访问的数据清出从而提高缓存命中率。目前已经存在的缓存置换算法包括 MRU (Most Recently Used)、MFU (Most Frequently Used)、LRU (Least Recently Used) 以及 LFU (Least Frequently Used) 等。每个算法都有其各自的适用场景。到目前为止,应用范围最广的是 LRU,主要原因在于 LRU 贴近大多数应用的实际负载模式 (workloads),同时 LRU 拥有 O(1) 时间复杂度的成熟实现方案。与 LRU 类似,LFU 同样与大多数应用的负载模式相近,但目前 LFU 最佳实现方案的时间复杂度是 O(logn) ,不如 LRU。本文,我们提出一种同样达到 O(1) 时间复杂度的 LFU 实现方案,它支持的操作包括插入、访问以及删除。

目录

本文将按顺序介绍:

  • LFU 的典型使用场景
  • LFU 的接口说明
  • 目前 LFU 的最佳实现方案
  • 时间复杂度为 O(1) 的 LFU 实现方案

    ...

    阅读全文 »

引言

中台是最近两年才出现的组织架构形式,一种新的组织架构形式必然会带来协作方式的改变,下面介绍伴鱼技术中台在发展过程中,技术中台内部以及技术中台与业务部门之间协作方式的探索过程,以及分享目前已经形成或正准备实践的最佳协作方式。

高效做事,专业的人做专业的事

基础设施平台化是中台化的基础阶段,伴鱼技术中台早期的时候,我们希望每个团队都能独立负责自己团队基础设施的平台化,比如数据库平台由DBA部门来负责建设,但是在实施的过程中出现比较多的问题:

  • 招聘很难,招聘研发能力强的DBA是不容易的,很难碰到合适的人,如果招聘研发能力比较勉强的DBA来做平台化,那么平台的质量很难得到保证;
  • 如果直接招聘研发工程师到DBA部门,但是数据库平台的开发不是一个需要长期不断研发的事情,一般是阶段性的研发需求,会导致的阶段性的人力过剩;
  • 特别是如果招聘的是经验比较浅的研发工程师,那么他们的培养与成长也会是一个问题。

经过一段时间的摸索后,我们通过临时项目组的方式解决了这样的问题,DBA做产品经理和项目经理,负责数据库平台的产品设计工作和项目管理的工作,在技术中台内部统一协调研发工程师来参与项目,项目完成后临时项目组解散,待下一次平台需要迭代的时候再重新组建项目组进行开发。

这样充分利用了DBA在数据库平台方面的专家经验,并且DBA是平台的使用者,所以数据库平台的产品形态和产品体验都是有保障的;让研发工程师来负责开发,并且研发工程师的 Leader 也会参与项目的讨论,这样平台的研发团队的专业性和质量都是非常有保障的;研发工程师由部门的研发 Leader 来管理,对研发工程师的成长与培养是有保证的。

通过上面的方式,确保了专业的人做专业的事,伴鱼的平台化推进的非常迅速和顺利,目前技术中台除了数据库平台外,运维方面的 CMDB 和 Paas 等平台都是按这个方式做的协作的,非常高效和高质量。

高效分享,既是技术评审也是技术分享

在伴鱼我们要求技术中台打造公司的技术氛围,做技术分享是一种很好营造公司技术氛围的方式,但是选择分享什么样的主题是一个很关键的地方,如果业务部门的工程师对分享的主题不感兴趣,那么大家要么不参加,要么参加后感觉没有收获,不管怎样都是一件非常浪费时间的事情。

在技术中台的发展过程中,我们发现研发工程师对于和他们非常相关的平台或者服务的技术评审是很感兴趣的,这样我们就找到切入点了,通过提高技术评审的质量,将技术分享融入技术评审,同时达到技术评审和技术分享的目的。

现在在伴鱼技术中台,每一个新项目的开发流程是这样的:

  • 项目的 Owner 负责调研国内外一线大厂的方案,特别是 Google、Facebook 等大厂的论文,然后结合我们的需求,形成技术方案的初稿;
  • 项目的 Owner 在组内进行技术评审,不论是作为技术评审还是技术分享质量都需要达到要求,才能算组内评审通过;
  • 在公司范围内发起该项目的技术评审,邀请大家来参加,由于是研发工程师非常关心的主题,所以大家的参与度会很高,并且技术评审又兼顾了技术分享,大家可以充分的讨论和交流,使得同时达到技术评审和技术分享的目的。而且良好的技术分享质量会建立起口碑,后续的技术评审业务部门研发工程师的参与意愿会更高。
  • 到这里还没有完,还有一个非常关键的部分,项目做完后,Owner 需要写一篇文章来对这个项目进行归纳和总结,这篇文章会放公司的技术博客上面,也会在公司范围内分享。

高效沟通,当面沟通与 OKR 对齐

技术中台和业务部门是两个独立的部门,业务部门需要依赖技术中台底层能力的支撑,所以如果技术中台和业务部门的沟通不顺畅,那么将是非常严重的问题,也很容易导致业务部门重新造轮子而导致技术中台的价值得不到体现,这将是技术中台部门最大的失败。

伴鱼技术中台在建设的过程中,我们对外非常鼓励业务部门的同事当面来反馈问题,对内强调 Feedback is a gift,确保技术中台和业务部门沟通流畅,通过沟通来解决问题。Feedback is a gift 也是伴鱼技术中台文化的一部分,是伴鱼技术中台人必须做到的事情。

短期和临时的问题,通过当面沟通来解决是非常不错的方式,但是对于长期规划的对齐,就显得力不从心了,通过每季度的 OKR 对齐会是一个非常好的方式。伴鱼是通过 OKR 来进行目标管理的,每一个季度的开始,技术中台和业务部门的研发同事会一起讨论和对齐大家的研发计划,确定业务部门这个季度需要技术中台提供的能力和服务,技术中台也会提一些需要业务部门进行升级解决技术债的需求,一起推动公司的技术进化。

高效响应,研发体验保障的关键

快速响应是研发体验的关键指标,这也是伴鱼技术中台早期就决定确保做到的关键点。将一些长期和关键的要求变成文化,通过文化潜移默化的方式去影响大家是伴鱼在这些事情上的做法,所以业务优先是伴鱼技术中台文化的第一条。现在大家在碰到排期问题的时候,业务优先是第一条需要考虑的准则。

高效响应业务,业务部门就会更愿意通过技术中台的能力来解决它们的问题,而不是自己造轮子。技术中台的目标是提供企业级的复用能力,很多时候,提供企业级的复用能力不是最难的地方,难的是业务部门愿意使用中台提供的能力,所以中台高效响应业务,是研发体验的保障的关键,也是实现中台目标的关键。

高效影响,值得一试的轮岗制度

这是本文中伴鱼技术中台唯一还没有实践但是一定会尝试的机制。其实这是受到一个偶然机会启发的,有一次业务部门找技术中台借调一个工程师去支持一个紧急需求,差不多一个星期的时间。在这一个星期中借调工程师发现了一些共性问题,业务部门有一些地方没有采用技术中台最新的技术方案,导致一些最新的能力没有在业务部门发挥出来,这是我们非常不期望的事情。

目前技术中台和业务部门的沟通其实是非常顺畅的,我们所有新的技术方案也会实时公告给业务部门,但是业务部门的关注点在业务迭代上,通知与公告这一类的浅影响是很难推动业务部门进行升级的,而轮岗却是一种非常深度的影响方式。一个业务工程师和一个中台工程师交换工作岗位一个星期,业务工程师到技术中台部门工作,充分了解目前技术中台的做事方式和最新的技术方案,中台工程师到业务部门工作,如果发现一些技术债务,则将目前技术中台最佳实践告诉大家,通过这种高效、深度的影响来拉齐中台和业务部门的技术实践方式。

高效调查,获得最直接的研发体验报告

技术中台做得好不好,唯一的评价指标就是研发体验,就像产品做的好不好,用户体验说了算一样。前面的每一条都是提高研发体验的方法,但是研发体验好不好,这个需要研发同事来回答,所以我们决定做研发体验调查。

目前技术中台的研发体验调查每季度一次,通过在线调查的方式进行,技术中台所有的平台和服务以及一些关键的体验指标比如沟通和响应等都是调查的内容,研发工程师对调查指标进行评分,技术中台通过对收集的调查数据进行分析来发现一些需要改进的问题。

特别是对于一些评分比较低的情况,项目的 Owner 需要找到评分研发同事进行一对一的深度沟通来了解评分低的原因,如果是理解的偏差,那么通过沟通解决,如果问题确实存在,那么记录下来并且给好解决问题的截止时间。

每一期的研发体验调查都会形成一个研发体验报告在公司内部公布,目前伴鱼技术中台进行了第一次的研发体验调查,平均评分最低的项目得分为4.3(5分制),这是一个非常好的开始,能获得业务部门研发同事的认可,对于技术中台来说是最一件非常值得骄傲的事情,当然我们还会努力做到更好。

总结

由于技术中台和业务部门是独立的部门,所以保证技术中台能够真正实现提供企业级的复用能力的关键除了技术因素外,中台和业务部门的协作方式也是一个非常重要的影响因素,本文从六个方面来描述了伴鱼技术中台和业务部门的协作方式:

  • 高效做事,专业的人做专业的事
  • 高效分享,既是技术评审也是技术分享
  • 高效沟通,当面沟通与 OKR 对齐
  • 高效响应,研发体验保障的关键
  • 高效影响,值得一试的轮岗制度
  • 高效调查,获得最直接的研发体验报告

并且,目前伴鱼技术中台通过上面的协作方式获得了研发部门非常好的研发体验评价。

引言

组织架构是围绕提高效率而设计的管理形式,任何新出现的组织架构一定是比之前的组织架构效率更高才有意义。中台是近来大家广泛讨论的一种组织架构,但是因为没有明确的定义,所以每一家公司对中台的理解可能会不尽相同。

但是不论什么样的组织架构,落到根本上都是服务好人才、做好事情,所以伴鱼在中台化落地的过程中,总是从这两个角度来评估当前组织架构对于效率的影响,以及应该怎么来优化当前的组织架构。本文回到组织架构的本质——效率的角度,分别从事情和人的角度讨论中台对组织架构的影响,以及伴鱼技术中台的建设与演进过程。

从事情的角度,中台组织架构应该关注提高复用率

每件事情只由一个团队负责

传统互联网公司的组织架构,一般是基于业务发展来设计的,开展新的业务线,组织架构是整体再建设一遍,这样会产生重复建设的问题。如果一个公司有多条业务线的时候,就会出现多个DBA团队,多个运维团队和多个基础架构团队等,这样一件事情在公司内部有多个团队负责,每个团队都需要独立做人才管理和技术积累,从事情的角度来看,复用率是非常低的。

一件事情只由一个团队负责,很多重复的事情只需要做一遍,减少了很多不必要的工作量,并且集中了全公司在这一个方面的人才和资源,这样才能很专业、深入和系统性地把这件事情做好。

...

阅读全文 »

一、理解公司业务

1、技术支撑业务的发展,业务成就技术的价值

技术中台聚集的是一群Geek,我们相信技术可以改变世界。但是一项技术的伟大,总是通过它的杀手级应用来体现;一家公司的伟大,总是因为做出了伟大的业务。不能支撑好业务的技术,依然有技术本身的价值,但这个价值会被局限,几乎很难释放出来。所以技术一定要服务好业务,做好业务的发动机,彼此配合才能相互成就。

技术中台最坏的状况是技术能力太差,不能支撑业务的发展,其次是技术脱离业务,不能服务业务的发展。前者是能力问题,后者是意识问题,伴鱼的技术中台一定是能力与意识俱佳的团队,所以我们必须要深入理解公司的业务。

...

阅读全文 »

一、当面沟通,高节奏沟通

1、选择最高效的沟通方式

口头沟通短期效率高但是长期效率低,文字沟通则正好相反。对于规范、流程等长期价值高的知识和经验,鼓励大家通过文档等文字沟通的形式来进行,而对于日常临时、突然等长期价值低的问题,鼓励大家通过当面口头沟通的形式,高效率沟通。

日常的工作内容,口头沟通的效率是高于通过钉钉和微信等软件沟通的,直接找到负责人的横向沟通的效率是高于向上汇报的纵向沟通的。非常推荐大家碰到临时、突发并且预计几分钟可以解决的问题时,找到事情的直接负责人,当面进行一个临时的站立会议,快速通过口头沟通达成一致。如果问题涉及的人数比较多,短时间内很难有结论,那么约一个正式的会议会是一个很好的选择。在沟通中达成一致的结论,如果有长期价值的结论,可以在沟通群中同步或者文档中心通过文字的形式记录下来。

...

阅读全文 »

一、 只招聘成年人

1、 成年人是指职业素养成熟的人

职业素养成熟的人,会遵守基本的规章制度,严格履行自己的承诺,是对自己有高要求的人。如果对于某些规章制度觉得不太合理,欢迎提出挑战,一起去推动规章制度的优化,在规章制度未修改之前,我们依然需要遵守它;我们对他人的承诺,一定要严格履行,如果因为种种原因确实无法完成,那么应该提前沟通,让对方了解不能完成的原因,并且争取对方的理解,做到凡事有交代,件件有着落,事事有回音;对自己有高要求,是自我成长的原始动力,我们只有事事提高要求,才能得到完美的结果,自己才能不断得到提高,对合作者也是良好的体验。

...

阅读全文 »

在kubernetes中要保证容器之间网络互通,网络至关重要。而kubernetes本身并没有自己实现容器网络,而是通过插件化的方式自由接入进来。在容器网络接入进来需要满足如下基本原则:

  • pod无论运行在任何节点都可以互相直接通信,而不需要借助NAT地址转换实现。
  • node与pod可以互相通信,在不限制的前提下,pod可以访问任意网络。
  • pod拥有独立的网络栈,pod看到自己的地址和外部看见的地址应该是一样的,并且同个pod内所有的容器共享同个网络栈。

容器网络基础

一个Linux容器的网络栈是被隔离在它自己的Network Namespace中,Network Namespace包括了:网卡(Network Interface),回环设备(Lookback Device),路由表(Routing Table)和iptables规则,对于服务进程来讲这些就构建了它发起请求和相应的基本环境。而要实现一个容器网络,离不开以下linux网络功能:

  • 网络命名空间: 将独立的网络协议栈隔离到不同的命令空间中,彼此间无法通信。
  • Veth Pair: Veth设备对的引入是为了实现在不同网络命名空间的通信,总是以两张虚拟网卡(veth peer) 的形式成对出现的。并且,从其中一端发出的数据,总是能在另外一端收到。
  • Iptables/Netfilter: Netfilter负责在内核中执行各种挂接的规则(过滤、修改、丢弃等),运行在内核中;Iptables模式是在用户模式下运行的进程,负责协助维护内核中Netfilter的各种规则表;通过二者的配合来实现整个Linux网络协议栈中灵活的数据包处理机制
  • 网桥: 网桥是一个二层网络虚拟设备,类似交换机,主要功能是通过学习而来的Mac地址将数据帧转发到网桥的不同端口上.

  • 路由: Linux系统包含一个完整的路由功能,当IP层在处理数据发送或转发的时候,会使用路由表来决定发往哪里

基于以上的基础,同宿主机的容器时间如何通信呢?

...

阅读全文 »

在计算机系统设计实践中,我们常常会遇到下图所示架构:

为了解决单个存储器读吞吐无法满足要求的问题,常常需要在存储器上面增加一个或多个缓存。但由于相同的数据被复制到一个或多个地方,就容易引发数据一致性问题。不一致的数据可能出现在同级 Cache 之间 (Cache Coherence) 上下级 Cache 之间。解决这些数据一致性问题的方案可以统称为 Cache Policies。从本质上看,所有 Cache Policies 的设计目的都可以概括为:在增加一级缓存之后,系统看起来和没加缓存的行为一致,但得益于局部性原理,系统的读吞吐量提高、时延减少

本文将探讨三个场景:

  1. Cache Policy In Single-core Processor
  2. Cache Coherence in Multi-core Processor
  3. Cache Policy in Cache/DB Architecture

    ...

    阅读全文 »

简介

本文是分布式系统理论的开山鼻祖、2013 年图灵奖获得者 Lamport 的成名作,也是分布式计算领域杰出论文最佳影响力奖 Dijkstra Prize 的第一篇论文,高达 11692 的引用量(截至 2019/12/08)足以证明其广泛的影响力:

本文主要讨论 3 个话题:

  • 分布式系统中的事件偏序
  • 利用逻辑时钟实现事件偏序
  • 利用逻辑时钟实现事件全序

    ...

    阅读全文 »

早在 2008 年,Google 就已开始分布式调用链追踪的工作,经过两年的打磨后,Dapper 系统问世,并通过这篇文章将其设计公之于众。遗憾的是,Dapper 并不是开源项目,但它的设计理念依然深刻影响到后来的 Jaeger、Zipkin 等开源分布式追踪项目,以及相关的标准 Opentracing、OpenTelemetry。

本文不是原文的精准翻译,而是一次重述和简述,旨在记录分布式调用链追踪要解决的核心问题和潜在解决方案。

Why & Design Goals

云原生环境中,一次请求的处理可能途径多个服务的任意实例,彻底理解系统就需要理解各服务内部的逻辑,理清这些服务之间的关系,甚至有时候还需要了解服务所在物理机的当时状态。系统出现异常时,如果其行为无法被追踪、被理解,就无法为解决异常快速提供线索。

通常这些异常会被监控捕捉,如时延异常、错误日志、程序崩溃,在紧急处理之后,就需要调查案发现场,彻底解决问题。这时候就需要了解每个请求在整个微服务集群内部的行踪。

这就向分布式追踪系统提出了两点要求:

  • 处处部署 (ubiquitous deployment)
  • 持续监控 (continuous monitoring)

如果部署不完全或者监控有间断,就可能有一小部分历史无法被追踪到,从而影响到问题定位的准确度,使得追踪效果大打折扣。

据此,我们提出追踪系统的 3 个主要设计目标:

  1. 低成本 (Low overhead):对服务的性能影响应该能够忽略不计
  2. 对应用透明 (Application-level transparency):应用开发者对追踪系统无感知
  3. 扩展性好 (Scalability):支持部署到所有服务的所有实例上

在此基础上,数据从采集到可以被查询、分析的延迟越小越好,起到的作用也越大、越及时。

How

General Approaches

分布式追踪的设计方案主要可以分为两类:黑盒法(black-box)和标记法(annotation-based):

黑盒法

黑盒法无需任何侵入性代码,只通过统计回归等手段来推测服务之间的关系。它的优势在于无需修改代码,缺点在于记录不准确,且需要大量数据才能够推导出服务间的关系。

标记法

标记法需要为每个请求打标记,并通过一个全局标识符将请求途径的所有服务信息串联,复盘整个链路。标记法记录准确,但它的缺点也很明显,需要将标记代码注入到每个服务中。

在 Google 内部,几乎所有应用都使用相同的 threading model、control flow 和 RPC systems,因此可以将打标记的工作集中在少量的公共库中,同样能够达到对应用透明的效果。

Data Models

通常一个请求在微服务集群中的调用链可以被抽象成树形结构,假设 RequestX 的处理过程如下图所示::

相应调用链追踪的树状结构为:

整棵树称为一个 trace,树上的节点称为 span。每个 span 都记录着 parent id 和 trace id,表明其所属父节点和调用链,其中没有 parent id 的 span 称为 root span,root span 的 id 就是 trace id。

每个 span 都需要记录其开始时间和结束时间,如果应用开发者有记录其它信息的需求,则可以手动增加相应的标记。

Pipeline

Dapper 记录、收集调用链信息的流水线主要分成 3 个阶段:

  1. span 数据写入本地日志文件
  2. dapper daemon 从本地日志文件中收集数据
  3. dapper collectors 将数据写入 Bigtable 的大区仓库 (regional repositories)

在 Bigtable 中,每行数据就是一个 trace,且每行可以有任意列,恰好方便存储不定长的 trace/span 数据。Dapper 向开发者提供相应的 API 和 SDK,方便 Google 的开发者能够据此搭建数据分析工具,定制化地辅助线上问题排查。

Overhead

调用链追踪的主要成本在于:trace generation 和 collection。

Trace generation

在 Dapper 中,生成 root span 需要 204 ns,生成 non-root span 需要 176 ns。这里面相差的部分就是生成 全局唯一 trace id 的时间成本。

在 Dapper 的 runtime library 中,最耗时的操作就是将 trace 信息写入本地磁盘,但考虑到使用批量和异步写入的方式优化,对被跟踪的服务本身的影响就相对削弱了。

Trace collection

Dapper daemon 需要从本地日志文件中读取 trace 信息,然后发送给 Dapper collectors。经过 benchmark 测试验证,Dapper daemon 从未使用超过单核 0.3% 的计算资源,且使用的内存空间极小,可忽略不计。同时 Dapper daemon 在 kernel scheduler 中的优先级被设置为最低,必要时会出让计算资源。

在实践中,平均每个 span 的大小约为 426 字节,经过计算,在生产环境中 Dapper 占用的网络带宽大约为总量的 0.01%。

Effect on production workloads

高吞吐的服务随时都会接收大量的请求,产生大量的 tracing 数据,而这类服务通常又是对性能最敏感的。下表中以 Google 的网页搜索服务集群为例,测量了不同的 trace 采样率对服务本身的影响:

其中 latency 和 throughput 的测量误差分别为 2.5% 和 0.15%。从图中可以发现,尽管调用链追踪带来的性能影响不是很大,但并不能忽略不计,对 trace 数据进行抽样是很有必要的。当抽样率小于 1/16 时,影响范围已经小于误差范围。在实践中,我们设置 1/1024 的抽样率就能收集到足够多的 trace 数据。

除此之外,使用更低的采样率可以让 trace 数据在本地磁盘存活更长的时间,为整个搜集框架争取更大的灵活度。

Adaptive Sampling

调用链追踪的成本与单位时间内收集的 trace 数量成正比。在 Dapper 的首个生产版本中,采用了统一的采样率 1/1024,这种固定采样率不会对高吞吐的在线服务产生不必要的影响。但在这样的采样率下,可能忽略掉一些发生不频繁的重要事件。

因此 Dapper 团队正在研发自适应采样率机制,针对不频繁的重要事件能提高采样率。实际被使用的抽样率会被记录在 trace/span 数据中,帮助后期工具分析。

Additional Sampling

上面介绍的均匀抽样和自适应抽样都是为了减少对被追踪服务本身性能的影响。但 Dapper 本身还需要控制整体抽样数据的规模,在论文发表时,Dapper 在生产环境中每天将产生 1T 的追踪数据;同时 Dapper 的用户希望追踪数据能够保持两周。因此这里存在着存储资源与追踪密度之间的权衡。除此之外,高抽样率也会提升 Dapper collectors、Bigtable 的吞吐量。因此 Dapper 团队引入了额外的一层抽样,来实现全局的、系统级的控制。

实现的思路很简单,将每个 trace id 哈希到 [0, 1],如果哈希值小于给定的抽样系数,则通过;大于则拦截。在实践中,额外的抽样给与 Dapper 团队更强的全局控制力。

Where

General-Purpose Tools

Dapper Depot API

Dapper 向开发者开放一系列 API:

  • Access by trace id
  • Bulk access
  • Indexed access

在实践中,Dapper 发现 (service_name, host_machine, timestamp) 的联合索引恰好能满足大部分开发者的需求。

Dapper user interface

dapper user interface 可以理解为 APM 系统,方便开发者快速对线上问题做根源分析。交互界面和 user story 详见论文。

Experiences

Using Dapper during development

Dapper 主要在以下几个方面帮助开发者改进服务:

  • Performance:通过调用链示意图发现服务瓶颈
  • Correctness:dapper 通过标签帮助开发者发现一些本该访问 master 节点的请求访问了 replicas
  • Understanding:dapper 帮助开发者理解自身系统的依赖,增进对复杂系统的理解,为架构层面优化提供依据
  • Testing:开发者可以通过观察调用链信息测试系统的行为是否符合预期

Addressing long tail latency

Google 内部的一位工程师利用 Dapper 提供的接口来推断服务的关键路径,进而减少服务整体时延。

Inferring service dependencies

服务之间的依赖关系常常是动态变化的,我们基本无法通过扫描配置信息、代码来确定服务之间的依赖关系。 Google 的 “Service Dependencies” 项目正是利用 Dapper 的近期数据来推断依赖关系。

Network usage of different services

在发现网络带宽使用异常时,Dapper 可以辅助开发者锁定到具体的请求。

Layered and Shared Storage Systems

一些公共服务通常很难知道其调用方及各自调用量,Dapper 帮助这些公共服务的维护者更好地了解它们。

References

Dapper