前言之前给小伙伴们科普ClickHouse集群的时候,我曾经提到ClickHouse集群几乎是去中心化的(decentralized),亦即集群中各个CK实例是对等的,没有主从之分。集群上的复制表、分布式表机制只是靠外部ZooKeeper做分布式协调工作。想了想,又补了一句:
“其实单纯靠P2P互相通信就能维护完整的集群状态,实现集群自治,比如Redis Cluster。”
当然限于时间没有展开说。这个周末休息够了,难得有空,来随便讲两句吧。
在官方Redis Cluster出现之前,要实现集群化Redis都是依靠Sharding+Proxy技术,如Twemproxy和Codis(笔者之前也写过Codis集群的事儿)。而官方Redis Cluster走了去中心化的路,其通信基础就是Gossip协议,同时该协议还能保证一致性和可用性。本文先来介绍一下它。
Gossip协议简介
最近几个月一直在看《Friends》下饭。认为自己从不gossip的Rachel一语道破了gossip的本质。
现实生活中的流言八卦传播的机制就是“I hear something and I pass th ...
关于redis的集群,官网介绍比较全面了。https://redis.io/topics/cluster-spec
设计目标:
High performance and linear scalability up to 1000 nodes. There are no proxies, asynchronous replication is used, and no merge operations are performed on values.
高达1000个节点的线性可扩展性。没有代理,使用异步复制,并且在进行赋值时没有合并操作
Acceptable degree of write safety: the system tries (in a best-effort way) to retain all the writes originating from clients connected with the majority of the master nodes. Usually there are small windows where acknowledge ...
之前做爬虫时,在公司设计开发了一个通用的垂直爬虫平台,后来在公司做了内部的技术分享,这篇文章把整个爬虫平台的设计思路整理了一下,分享给大家。
写一个爬虫很简单,写一个可持续稳定运行的爬虫也不难,但如何构建一个通用化的垂直爬虫平台?
这篇文章,我就来和你分享一下,一个通用垂直爬虫平台的构建思路。
爬虫简介首先介绍一下,什么是爬虫?
搜索引擎是这样定义的:
网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取网页信息的程序或者脚本。
很简单,爬虫就是指定规则自动采集数据的程序脚本,目的在于拿到想要的数据。
而爬虫主要分为两大类:
通用爬虫(搜索引擎)
垂直爬虫(特定领域)
由于第一类的开发成本较高,所以只有搜索引擎公司在做,如谷歌、百度等。
而大多数企业在做的都是第二类,成本低、数据价值高。
例如一家做电商的公司只需要电商领域有价值的数据,那开发一个只采集电商领域数据的爬虫平台,意义较大。
我要和你分享的主要是针对第二类,垂直爬虫平台的设计思路。
如何写爬虫首先,从最简单的开始,我们先了解一下如何写一个爬虫?
简单爬虫开发爬虫最快的语言一般是 Python ...
(0) ChannelPipeline的实例
ChannelPipeline的使用实例
12345678910111213141516171819202122private void connect(String host,int port){ EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketCha ...
1.什么是Lucene?
作为一个开放源代码项目,Lucene从问世之后,引发了开放源代码社群的巨大反响,程序员们不仅使用它构建具体的全文检索应用,而且将之集成到各种系统软件中去,以及构建Web应用,甚至某些商业软件也采用了Lucene作为其内部全文检索子系统的核心。apache软件基金会的网站使用了Lucene作为全文检索的引擎,IBM的开源软件eclipse的2.1版本中也采用了Lucene作为帮助子系统的全文索引引擎,相应的IBM的商业软件Web Sphere中也采用了Lucene。Lucene以其开放源代码的特性、优异的索引结构、良好的系统架构获得了越来越多的应用。
Lucene作为一个全文检索引擎,其具有如下突出的优点:
(1)索引文件格式独立于应用平台。Lucene定义了一套以8位字节为基础的索引文件格式,使得兼容系统或者不同平台的应用能够共享建立的索引文件。
(2)在传统全文检索引擎的倒排索引的基础上,实现了分块索引,能够针对新的文件建立小文件索引,提升索引速度。然后通过与原有索引的合并,达到优化的目的。
(3)优秀的面向对象的系统架构,使得对于Lucene扩展的学习难度 ...
(0) Reactor模型
Reactor模型是一种经典的线程模型,一般分为三种类型:
Reactor单线程模型
Reactor多线程模型
Reactor主从多线程模型
Reactor单线程模型
Reactor单线程模型是指所有的IO操作包括acceptor操作和handler操作都由一个线程完成;
Netty中Reactor单线程的实现
1234ServerBootstrap b = new ServerBootstrap();EventLoopGroup group = new NioEventLoopGroup(1); //创建只有一个线程的线程池b.group(group); //acceptor操作和handler操作共用group线程池中的一个线程;
单线程模型适用在小容量,低并发的应用场景上,对于高负载高并发的应用场景不适用:
如果handler操作是计算密集型操作,在高并发情况下即便CPU负荷达到100%也可能完成不了海量数据的处理,这就可能造成消息堆积和延迟处理;
如果handler操作中出现阻塞则可能会导致acceptor操 ...
引言书接上文,前面我们分别介绍了 Dubbo 的设计思想,分析了微内核的实现方案,服务导出与引入、以及集群容错方面的代码。经过前文的铺垫,本篇文章我们终于可以分析服务调用过程了。
技术内幕实现细节服务调用过程在前面的文章中,我们分析了 Dubbo SPI、服务导出与引入、以及集群容错方面的代码。经过前文的铺垫,本篇文章我们终于可以分析服务调用过程了。Dubbo 服务调用过程比较复杂,包含众多步骤,比如发送请求、编解码、服务降级、过滤器链处理、序列化、线程派发以及响应请求等步骤。接下来我们将会重点分析请求的发送与接收、编解码、线程派发以及响应的发送与接收等过程。
首先服务消费者通过代理对象 Proxy 发起远程调用,接着通过网络客户端 Client 将编码后的请求发送给服务提供方的网络层上,也就是 Server。Server 在收到请求后,首先要做的事情是对数据包进行解码。然后将解码后的请求发送至分发器 Dispatcher,再由分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务。这就是一个远程调用请求的发送与接收过程。至于响应的发送与接收过程,这张图中没有表现出来。对于这两 ...
一、Future模式Java 1.5开始,提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。
Future接口可以构建异步应用,是多线程开发中常见的设计模式。
当我们需要调用一个函数方法时。如果这个函数执行很慢,那么我们就要进行等待。但有时候,我们可能并不急着要结果。
因此,我们可以让被调用者立即返回,让他在后台慢慢处理这个请求。对于调用者来说,则可以先处理一些其他任务,在真正需要数据的场合再去尝试获取需要的数据。
1、Callable与Runnablejava.lang.Runnable是一个接口,在它里面只声明了一个run()方法,run返回值是void,任务执行完毕后无法返回任何结果
123public interface Runnable { public abstract void run();}
Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法叫做call(),这是一个泛型接口,call()函数返回的类型就是传递进来的V类型
123public in ...
数据结构
未读翻译自http://www.h2database.com/html/mvstore.html
转载请著名出处,及译者信息。
第一次翻译,诸多不妥请谅解,谢谢。
概述MVStore是一个持久化的、日志结构式的kv存储。本计划用它作为H2的下一代存储子系统,但你也可以在一个不涉及JDBC或者SQL的应用中直接使用它。
MVStore代表多版本存储。
每一个store包含大量的map,这些map可以用java.util.Map接口存取。
支持基于文件存储和基于内存的操作。
它希望更快,更简单的使用,更小。
支持并发读写操作。
支持事务(包括并发事务与两阶段提交(2-phase commit))
模块化的工具,支持插拔式的数据类型定义、序列化实现,支持插拔式的存储载体(存到文件里、存到堆外内存),插拔式的映射实现(B-tree,R-tree,当前用的concurrent B-tree),BLOB存储,文件系统层的抽象以使其支持文件的加密与压缩
示例代码1234567891011121314import org.h2.mvstore.*;// open the store (in-memor ...
在之前的一个系列的文章里,我们从基本原理开始,一步步实现了基于 Vector Trie 的持久化 List 数据结构。 接下来将要研究的是使用 HAMT 这一数据结构实现持久化 Hash Table。
持久化数据结构简介 这篇文章里, 我们对比各种可以用来实现持久化数据结构的方案,详细介绍了 Vector Trie 这种数据结构,说明了用它实现 List 优势。 HAMT 的全称是 Hash Array Mapped Trie,它和 Vector Trie 一样,都利用了前缀树(Trie)这种数据结构作为底层数据结构, 但是由于 Map 本身和 List 之间性质的差别,HAMT 在很多方面进行了特别的处理。接下来我们先从原始 Hash Table 数据结构谈起, 逐步引出 HAMT 的设计原理。
Hash TableHash Table 是利用对象的 Hash 值对所储存的键进行散列从而实现快速的插入、删除和访问的数据结构。 在 Go 语言中的 map、Java 中的 HashTable 和 HashMap 和 Python 当中的 dict 都是 HashTable 的一种。 其基 ...

