使用场景
- 问题排查
在分布式系统中,同一个应用可能部署在多台机器上,如果日志没有集中搜集起来,通过日志排查问题时需要查找每台机器上的日志,排查过程也会消耗性能,可能影响线上业务。
- 离线场景
日志可用来统计PV、UV 等指标,用于 OLAP、机器学习模型训练等场景。
- 实时场景
可用日志流中实时解析出有价值的信息,用于实时 OLAP、实时模型训练、风控等。
问题挑战
- 数据量大
- 业务线多
- 易用性,无侵入
Flink 核心是一个流式的数据流执行引擎,针对数据流的分布式计算提供了数据分布、数据通信以及容错机制等功能。
在执行引擎这一层,流处理系统与批处理系统最大不同在于节点间的数据传输方式。对于一个流处理系统,其节点间数据传输的标准模型是:当一条数据被处理完成后,序列化到缓存中,然后立刻通过网络传输到下一个节点,由下一个节点继续处理。而对于一个批处理系统,其节点间数据传输的标准模型是:当一条数据被处理完成后,序列化到缓存中,并不会立刻通过网络传输到下一个节点,当缓存写满,就持久化到本地硬盘上,当所有数据都被处理完成后,才开始将处理后的数据通过网络传输到下一个节点。这两种数据传输模式是两个极端,对应的是流处理系统对低延迟的要求和批处理系统对高吞吐量的要求。Flink的执行引擎采用了一种十分灵活的方式,同时支持了这两种数据传输模型。Flink以固定的缓存块为单位进行网络数据传输,用户可以通过缓存块超时值指定缓存块的传输时机。如果缓存块的超时值为0,则Flink的数据传输方式类似上文所提到流处理系统的标准模型,此时系统可以获得最低的处理延迟。如果缓存块的超时值为无限大,则Flink的数据传输方式类似上文所提到批处理系统的标准模型,此时系统可以获得最高的吞吐量。同时缓存块的超时值也可以设置为0到无限大之间的任意值。缓存块的超时阈值越小,则Flink流处理执行引擎的数据处理延迟越低,但吞吐量也会降低,反之亦然。通过调整缓存块的超时阈值,用户可根据需求灵活地权衡系统延迟和吞吐量。
Flink 在流式引擎的基础上实现了流处理和批处理。窗口(window)是从 Streaming 到 Batch 的一个桥梁。
在分布式系统中,不能把数据放在同一个节点上导致单点故障。但是把同一份数据存放在多个节点,可能引起不同节点数据不一致问题。
分布式一致性算法就是为了解决分布式系统中不同节点的一致性问题。
分布式一致性算法可以分为强一致性算法和弱一致性算法两类。
数据跟新后同步到集群中所有节点,客户端不会查询到不一致数据,常见的强一致性算法有:Paxos、Raft(muti-paxos)和 ZAB(muti-paxos)
集群各节点数据达到完全一致需要一个过程,该过程中客户端可能查询到不一致数据,常见的弱一致性算法有
zk 写不是可扩展的,不可以通过加节点来解决水平扩展的问题
分布式系统里,最重要的事情,就是如何选择或设计适合的算法,解决一致性和可用性相关的问题了。InfluxDB企业版本的技术壁垒就是以分布式算法为核心的分布式集群能力。有些人在接入性能敏感的场景,该使用反熵(Anti-Entropy)算法的时候,却用了 Raft 算法,使得集群性能约等同于单机。
CAP 理论对分布式系统的特性做了高度抽象,形成了三个指标:
一致性说的是客户端的每次读操作,不管访问哪个节点,要么读到的都是同一份最新写入的数据,要么读取失败。一致性这个指标,描述的是分布式系统非常重要的一个特性,强调的是数据正确。也就是说,对客户端而言,每次读都能读取到最新写入的数据。
可用性说的是任何来自客户端的请求,不管访问哪个非故障节点,都能得到响应数据,但不保证是同一份最新数据。我尽力给你返回数据,不会不响应你,但是我不保证每个节点给你的数据都是最新的。这个指标强调的是服务可用,但不保证数据正确。
分布式系统与单机系统不同,它涉及到多节点间的通讯和交互,节点间的分区故障是必然发生的,所以我要提醒你的是,在分布式系统中分区容错性是必须要考虑的。
只要有网络交互就一定会有延迟和数据丢失,而这种状况我们必须接受,还必须保证系统不能挂掉。所以就像我上面提到的,节点间的分区故障是必然发生的。也就是说,分区容错性(P)是前提,是必须要保证的。
只剩下一致性(C)和可用性(A)可以选择了:要么选择一致性,保证数据正确;要么选择可用性,保证服务可用。那么 CP 和 AP 的含义是什么呢?
在不存在网络分区的情况下,也就是分布式系统正常运行时(这也是系统在绝大部分时候所处的状态),就是说在不需要 P 时,C 和 A 能够同时保证。只有当发生分区故障的时候,也就是说需要 P 时,才会在 C 和 A 之间做出选择。而且如果读操作会读到旧数据,影响到了系统运行或业务运行(也就是说会有负面的影响),推荐选择 C,否则选 A。
junit常见注解含义以及执行顺序
@Before:初始化方法 对于每一个测试方法都要执行一次(注意与BeforeClass区别,后者是对于所有方法执行一次)
@After:释放资源 对于每一个测试方法都要执行一次(注意与AfterClass区别,后者是对于所有方法执行一次)
@Test:测试方法,在这里可以测试期望异常和超时时间
@Test(expected=ArithmeticException.class)检查被测方法是否抛出ArithmeticException异常
@Ignore:忽略的测试方法
@BeforeClass:针对所有测试,只执行一次,且必须为static void
@AfterClass:针对所有测试,只执行一次,且必须为static void
一个JUnit4的单元测试用例执行顺序为:
@BeforeClass -> @Before -> @Test -> @After -> @AfterClass;
秒杀系统是电商系统常见的一个功能,电商平台通过推出秒杀性价比高的活动短时间内吸引大量用户参与。从技术角度看,秒杀系统需要应对如下几个挑战:
前端动静分离,把90%的静态数据缓存在用户端或者CDN上,当真正秒杀时用户只需要点击特殊的按钮“刷新抢宝”即可,而不需要刷新整个页面,这样只向服务端请求很少的有效数据,而不需要重复请求大量静态数据。
网站负载均衡层或业务网关层需要能够对访问请求按用户粒度进行流量限制,以降低抢购脚本对系统带来的压力。
在安全方面,通过高防CDN或高防IP,降低DDOS攻击的影响。
在业务方面,通过引入答题环节,将突然涌入的压力平滑到3s左右的时间段内。
领域驱动设计应对复杂问题的思想可以归类为:分治、抽象和知识。
分治: 把问题空间分割为规模更小且易于处理的若干子问题。分割后的问题需要足够小,而且具有边界。
抽象:对业务进行高度的归纳概括,对具体场景总结提炼,提取出关键的特征。
知识: 模型是对知识的提炼与转换,领域驱动中设计的模型本身是具备业务含义的。
通用语言是团队,包括产品、开发、测试共享的语言。由于通用语言最初来自业务方或者产品,在技术人员评审的过程中,产生分歧是难免的,这需要反复沟通来确认是否达成了共识。通用语言不仅仅是领域驱动设计开发的基础,也是软件开发的基础。通用语言不仅仅是词汇表,它要表达具体的业务场景,以及该场景的意图以及价值。通用语言形成是开发和产品不断的基于业务的目标和价值来挖掘业务场景,并将其准确表达出来的过程。
领域具体指一种特定的范围或区域。领域是用来确定范围的,范围即边界。广义上讲,领域(Domain)是一个组织所做的事情以及其中所包含的一切。每个组织都有自己的业务范围和做事方式,这个业务范围及在其中所做的活动便是领域。在研究和解决业务问题时,领域驱动设计会按照一定的规则将业务领域进行细分,当领域细分到一定的程度后,领域驱动设计会将问题范围限定在特定的边界内,在这个边界内建立领域模型,进而用代码实现该领域模型,解决相应的业务问题。一个大的领域可以先划分为子领域,我们把划分出来的多个子领域称为子域,每个子域对应一个更小的问题域或更小的业务范围。领域建模的核心思想就是将问题域逐步分解,降低业务理解和系统实现的复杂度。
通过子域划分,根据不同子域对业务的不同功能属性和重要性可以区分为核心域、支撑域和通用域。对于核心域,是业务成功的主要促成因素;支撑域是相对于通用域来说的,某些领域不能通用而需要定制化,这样的领域被称为支撑域。如果一个领域能够应用于整个业务系统便是通用子域。以打车软件为例,它的核心域应该是连接距离最近的用户和司机,而软件中的地图系统则为通用域,地图系统可以使用腾讯地图提供的开放接口;而对于腾讯地图来说,地图系统则是他们的核心域。
限界上下文是一个显式的边界,领域模型便存在于这个边界之内。领域模型把通用语言表达成软件模型。创建边界的原因在于:每一个模型概念,包括它的属性和方法,在边界之内都具有特殊含义,而在另一个边界里面可能表达不同的含义。
Storm 是一个开源的分布式、实时、可扩展、容错的计算系统,Storm 可以可靠地处理无限数据流,像 MapReduce 和 Spark 批量处理离线数据一样。可用于实时分析、在线机器学习、连续计算、分布式 RPC、ETL 等。
Storm 分布式集群主要由一个控制节点(Nimbus 节点)和多个工作节点(Supervisor节点)组成。
Zookeeper负责Nimbus 和Supervisor 节点之间的协调工作
Nimbus节点负责资源分配和任务分配,通过Zookeeper监控Supervisor状态,Supervisor节点定期接受Nimbus节点分配任务,并会从Nimbus下载代码,启动对应的worker进程并监控worker 状态,每一worker是一个独立的JVM进程,Worker中运行Spout/Bolt线程Task任务,Storm使用zookeeper来协调整个集群,状态信息(Nimbus分发的任务、Supervisor、worker的心跳等)都保存在Zookeeper上。
$F1=(2PR)/(P+R)$

很多学习器是为测试样本产生一个实值或概率预测,然后将这个预测值与分类阈值进行比较,如果大于阈值为正例,反之为负例。根据这个预测值(概率预测结果),可以将测试样本进行排序,最可能是正例的排在最前面,最不可能是正例的排在最后面。
在不同应用中,可根据任务需求采用不同截断点,如果更重视准确率,可选择排序中靠前的位置进行截断,如果更重视召回率,可选择靠后的位置进行截断。
ROC受试者工作特征(Receiver Operating Characteristic)曲线,与 P-R曲线使用准确率和召回率为纵、横坐标不同,ROC 曲线的纵轴是真正例率(True Positive Rate,TPR),横轴是假正例率(False Positive Rate,FPR)。
$TPR = \cfrac{TP} {TP + FN}$
$FPR = \cfrac{FP} {FP + TN}$
构建一个长度为$2^{32}$ 的整数环(一致性 hash 环),根据节点名称的 hash 值(范围[0, $2^{32} - 1$])将服务节点放在 hash 环上,根据数据 key 值计算得到 hash 值(范围也是[0, $2^{32} - 1$]),接着在 hash 环上顺时针查找距离 key 的 hash 值最近的服务器节点,完成 key 到服务器的映射查找。
一致性 hash 算法解决了普通余数 hash 算法伸缩性差的问题,可以在服务器上线、下线情况下尽量有多的请求命中原来路由的服务器。