技术

谈谈Kafka中CAP定理的实践

如今绝大部分项目,大部分都是采用的分布式系统架构。分布式系统可以防止系统突然宕机导致服务整体不可用,可以从容的应对高并发请求,从而提高系统的可用性。但是如果实现一个分布式系统,经过一段时间的编码和设计,其实会发现并没有这么简单。

相比于单机系统,分布式系统需要多台服务器,而服务器之间的通信是需要绝对保障的;如果通信超时,会影响项目的正常运行;如果是分布式存储系统(不仅仅是),写入的数据也需要被同步到多台服务器上,数据更新肯定是有一定的延迟的,怎么权衡延迟时间和数据实时性的要求更需要被考虑;如果是Leader服务器宕机了,follower服务器需要立刻自动切换角色,提供服务,且要保证数据一致性等等,这些都是在分布式系统设计中需要被面对的问题。

有没有一个架构或框架,能够解决在分布式系统中面临的问题?答案是没有。这个问题起源于加州大学柏克莱分校(University of California, Berkeley)的计算机科学家埃里克·布鲁尔(Eric Brewer),在2000年的分布式计算原理研讨会(PODC)上提出的猜想。但在2002年,麻省理工学院的赛斯·吉尔伯特和南希·林奇证明了布鲁尔的猜想,使之成为一个定理,这个就是CAP定理(CAP theorem),也被称作布鲁尔定理(Brewer’s theorem)。

Kafka是一个典型的分布式系统,涉及到数据存储和数据传递(通信),Kafka在设计和开发的过程中,是怎么合理的解决分布式系统普遍面临的这些问题的呢?那么今天的这篇文章,来谈谈CAP理论在Kafka中的实践。

Kafka日志消息解析

我们知道,写入kafka的消息都需要指定一个Topic(主题),Kafka可以根据Topic来对消息进行区分,每个Topic分为多个Partition(分区)。

Partition的概念是为了实现高伸缩性和提供负载均衡的作用,可以很好的让一个比较大的(数据量级)Topic中的消息可以分布到多台broker机器上。不仅如此,也可以提高并行能力,因为水平扩展后可以以Partition为粒度进行读写,这样每个broker节点都能独立执行各自分区的读写请求;

Partition下就是Log的消息体,每条消息都只会保存在某一个分区中,而且在每个Partition下消息都是append模式写入的,也就是说,每个Partition下的消息都是顺序性的。

Kafka消息设计方式就是这样的三层结构:主题-分区-消息;说到设计,不同的分布式系统对分区的叫法也不大一样,在Kafka中的概念是Partition(分区),在ES中叫做Shard(分片),而在HBase中被称为Region。从表面上来看实现原理可能不尽相同,但对底层实现的思想却都是一致的。

话题扯回来,今天这篇文章分享的主题是:Kafka消息格式。

Kafka无消息丢失配置

今天这篇文章分享的主题是:Kafka无消息丢失配置,以及分析一些常见的消息丢失案例。

在这之前,我们需要清楚,Kafka丢失消息的几种场景。比如:producer生产者把消息写入topic中,broker端并没有接收到,消息在去的路上丢失了;broker端接收到了消息,但是consumer并没有消费到这条数据,消息在broker端丢失了;broker端接收到了消息,但是consumer消费者并没有消费到,消息在来的路上丢失了。

这几种场景其实就是Kafka架构决定的。

Kafka为什么快

今天这篇文章分享的主题是:Kafka为什么速度这么快?

快是基于比较得出来的,相对与其它消息队列或消息引擎,在很多讲解Kafka的文章都会提到这一点:Kafka可以很轻松的支持每秒百万级的TPS请求,其实在实际的基准测试中,每秒写入速率高达两百万,这远远高于其它消息队列的测试数据,Kafka在大数据消息队列组件中也是不二之选,并且绝大多数的大数据计算组件都与kafka进行集成。

但实际生产中的性能数据会受很多参数和环境的影响,比如acks设置:在保证数据不丢失的情况下,设置acks=all,吞吐量会明显降低;replication副本数量:副本数越多,吞吐量越低;batch大小:batch-size大小达到阈值时,会达到吞吐量峰值,超过阈值后,并不会提升性能;和压缩设置等等因素都可以影响Kafka吞吐量。

我们知道,Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写是相对而言是较慢的,因为磁盘寻址是相对需要消耗大量的时间,那为什么Kafka速度还是这么快?我们得从Kafka写入为什么这么快Kafka消费为什么这么快两方面,深入解析下Kafka主要的技术原理。

SparkStreaming之解析mapWithState

最近经历挫折教育,今天闲得时间,整理状态管理之解析mapWithState。今天说道的mapWithState是从Spark1.6开始引入的一种新的状态管理机制,支持输出全量的状态和更新的状态,支持对状态超时的管理,和自主选择需要的输出。

SparkStreaming之解析updateStateByKey

说到Spark Streaming的状态管理,就会想到updateStateByKey,还有mapWithState。今天整理了一下,着重了解一下前者。

状态管理的需求

举一个最简单的需求例子来解释状态(state)管理,现在有这样的一个需求:计算从数据流开始到目前为止单词出现的次数。是不是看起来很眼熟,这其实就是一个升级版的wordcount,只不过需要在每个batchInterval计算当前batch的单词计数,然后对各个批次的计数进行累加。每一个批次的累积的计数就是当前的一个状态值。我们需要把这个状态保存下来,和后面批次单词的计数结果来进行计算,这样我们就能不断的在历史的基础上进行次数的更新。

SparkStreaming提供了两种方法来解决这个问题:updateStateByKey和mapWithState。mapWithState是1.6版本新增的功能,官方说性能较updateStateByKey提升10倍。

Apache-Thrift-Thrift-Thrift

接着上篇文章说。

我们知道了Apache Thrift主要用于各个服务之间的RPC通信,并且支持跨语言;包括C++,Java,Python,PHP,Ruby,Go,Node.js等等,还有一些都没听说过的语言;而且从上篇文章的RPC例子中可以发现,Thrift是一个典型的CS(客户端/服务端)架构;加上跨语言的特性,我们可以推断一下:客户端和服务端是可以使用不同的语言开发的。

如果CS端可以使用不同的语言来开发,那么一定是有一种中间语言来关联客户端和服务端(相同语言也需要关联客户端和服务端)。其实这个答案都知道,那就是接口定义语言:IDL(Interface Description Language);下面我们从IDL进行开场表演,进行一次Thrift RPC的完整演出。

远程过程调用

原本是写一篇Apache Thrift in HiveServer,改写JDBC连接Hive相关应用的推文,因为HiveServer是使用Thrift提供服务创建网络RPC的多种语言客户端;单独拿出来说,使用Thrift也可以轻松构建RPC服务器,是轻量级的跨语言的远程服务调用框架。说到远程过程调用,感觉又要解释很多,所以就先上个前菜,说一说远程过程调用(RPC);并加了一份佐料:关于JDBC连接Hive的实现。

理解Spark核心之RDD

Spark是围绕RDD的概念展开的,RDD是可以并行操作的容错元素集合。RDD全称是Resilient Distributed Datasets(弹性分布式数据集)

理解RDD

如果你在Spark集群中加载了一个很大的文本数据,Spark就会将该文本抽象为一个RDD,这个RDD根据你定义的分区策略(比如HashKey)可以分为数个Partition,这样就可以对各个分区进行并行处理,从而提高效率。

Spark的运行模式

Spark是新一代基于内存的计算框架,是用于大规模数据处理的同意分析引擎。相比于Hadoop MapReduce计算框架,Spark将中间计算结果保留在内存中,速度提升10~100倍;同时采用弹性分布式数据集(RDD)实现迭代计算,更好的适用于数据挖掘、机器学习,极大的提升开发效率。

Spark的运行模式,它不仅支持单机模式,同时支持集群模式运行;这里具体的总结一下Spark的各种运行模式的区分。

Local模式

Local模式又称本地模式,通过Local模式运行非常简单,只需要把Spark的安装包解压后,改一些常用的配置即可使用,而不用启动Spark的Master、Worker进程(只有集群的Standalone模式运行时,才需要这两个角色),也不用启动Hadoop的服务,除非你需要用到HDFS。

使用Swagger2构建RESTful API

吐槽了一阵公司提供的记录接口文档工具后,抽个空档时间搭了个RESTful风格的API文档Demo,感觉还不错,在这里记录一下,技术栈使用Spring Boot+Swagger2。

Swagger可以很轻松的整合到Spring Boot中,在代码里根据swagger语法打些标签,生成可预览的Api文档,减少了很多时间写API接口文档上,让维护文档和修改代码整合一体了,并且可以与Spring MVC程序配合组织出强大RESTful API文档,也能提供了强大的页面测试功能来调试测试每个接口。

几种定时调度的介绍与实现

由需求产出的一篇文章,憋了很久。以下将会看到,使用Timer进行任务调度,用ScheduledExecutor和Calendar实现任务调度,Spring中的任务调度TaskScheduler,开源工具包Quartz的简单介绍。

使用Timer任务调度

Timer是java.util.Timer提供的比较简单的调度工具,实现任务调度的核心是Timer和TimerTask。其中Timer负责在schedule方法中设定TimerTask任务,以及任务执行的起始时间delay和间隔执行的时间period;TimerTask负责创建需要调度的任务,开发者需要实现run方法,然后将其丢给Timer去执行即可。

Java线程池

虽然之前学习了不少相关知识,但是只有在实践中踩坑才能印象深刻。今天看了半天的java对线程池的处理,额外兴致来,总结一份java线程池相关。

HDFS NameNode内存全景

在HDFS系统架构中,NameNode管理着整个文件系统的元数据,维护整个集群的机架感知信息和DataNode和Block的信息,Lease管理以及集中式缓存引入的缓存管理等等。从整个HDFS系统架构上来看,NameNode是最重要、最复杂也是最容易出现问题的地方。

NameNode概述

NameNode管理的HDFS文件系统的元数据分为两个层次:NameSpace管理层,负责管理文件系统中的树状目录结构以及文件与数据块之间的映射关系;块管理层,负责管理文件系统中文件的物理块与实际存储位置的映射关系(BlockMap)。

HDFS核心API编程案例

  • 删除HDFS集群中所有的空文件和空目录
  • 使用流的方式上传下载文件
  • 统计HDFS文件系统中文件大小小于HDFS集群中默认块大小的文件占比
  • 统计出HDFS文件系统中平均副本数

Hadoop HA集群搭建

HA:High Available,高可用。为什么需要HA机制?怎么配置HA?

为什么会有Hadoop HA机制

在HDFS集群中NameNode会存在单点故障(SPOF:A Single Point of Failure)问题:对于只有一个NameNode的集群,如果唯一的NameNode机器出现故障,比如宕机、软件硬件升级等。那么整个集群将无法使用,直到NameNode重新启动才会恢复。

所以在hadoop2.0之前,出现这种单节点故障问题是无法解决的;但是Hadoop HA机制的出现就很好的解决了这个问题,在一个典型的Hadoop HA集群中,使用两台单独的机器配置为NameNodes节点。在任何时间点,确保NameNodes中只有一个处于Active状态,另一个处在Standby状态。其中ActiveNameNode负责集群中所有的客户端的操作,StandbyNameNode仅仅充当备机,保证一旦ActiveNameNode出现问题能够快速切换。

Hibernate核心配置文件总结

  • 引入约束

  • 连接数据库(重点)

  • Hibernate中其他配置

  • 引入映射文件(必须)

按照hibernate核心文件配置的顺序是以上的排序。我现在以步骤的重要的先后顺序来按点讲解,顺便也当自己复习和回顾。