搭建一套hadoop伪分布式搭建存储大概需要多少钱

如何利用Node.js 构建分布式集群
发表于 16:10|
来源新闻资讯|
作者新闻资讯
摘要:在软件定义的世界里,企业通过Web应用和移动应用程序来提供大部分的服务,Node.js迅速成为时下最为流行的一个平台之一,就和它可以搭建响应速度快、易于扩展的web应用和移动应用有很大关系,并凭借这点成为了新的主流。作为大规模使用Node.js 的云计算服务提供商,UCloud积累了丰富的使用经验。
在软件定义的世界里,企业通过Web应用和移动应用程序来提供大部分的服务,Node.js迅速成为时下最为流行的一个平台之一,就和它可以搭建响应速度快、易于扩展的web应用和移动应用有很大关系,并凭借这点成为了新的主流。作为大规模使用Node.js 的云计算服务提供商,UCloud积累了丰富的使用经验。
本文为UCloud公司高级工程师文天乐在深JS大会上发表的演讲内容,主要介绍了UCloud内部如何利用Node.js 构建分布式集群,并分享了实践过程中走过的坑,希望对正在使用Node.js或是即将使用Node.js的朋友有一些帮助。
图:UCloud高级工程师文天乐
UCloud内部大规模使用了Node.js 技术,利用Node.js研发了一套RPC框架,主要涉及API、Web Console、服务中间层、运营报表、内部运营工具和内部系统等,解决以下四个问题:
1. 服务调动发现程序间解耦;
2. 自动快速扩容服务能力;
3. 脚本语言提高研发效率;
4. 配置集中管理变更应用自动加载。
在RPC框架V1版本的架构中,如下图。从图中可以看出,是一个金字塔架构,也就意味所有通信服务需要首先和名字服务进行通信,获取到对端节点状态和IP端口信息,然后再进行通信,这样导致系统的高耦合,增加了系统的复杂性,这并不是一件好事。
为此,我们改进了RPC框架架构,如图2。在V2版本中,可以看到改进的架构已是一个网状架构,实现了将所有消息出入口统一到RabbitMQ Server ,以便所有的通信可以在不知道对端节点状态时,就可以调用对端服务,从而实现了服务端调用关系解耦。
那么到底是如何实现服务端调用解耦的呢?在实现方案中,我们采用了(Node.js + Protocol Buffers + Zookeeper + RabbitMQ)的组合,从而实现配置集中化管理:
1.Node.js,主要用于开发业务逻辑。
作为天生的异步脚本语言,Node.js 使用事件驱动、 非阻塞I/O模型大大提升了研发效率,非常适合在分布式设备上运行的数据密集型的实时应用。
我们通过 Fibers库采用协程的方式来解决Node.js 异步编程匿名回调问题,将异步回调逻辑转化为同步,同时也满足了程序员使用同步方法编写异步程序的情怀。
可参考官方介绍:&https://nodejs.org/
/laverdet/node-fibers
2.Protocol Buffers,用于强约束消息定义。
Protocol Buffers一种数据交换的格式,它独立于语言,独立于平台。由于它是一种二进制的格式,相比XML和JSON,传输效率会更高,可以将它用于分布式应用之间的数据通信或者异构环境下的数据交换。我们主要将Protocol Buffers用来模版化定义消息结构。
可参考:&/google/protobuf
3.Zookeeper,实现配置集中管理。
Zookeeper分布式服务框架是Apache Hadoop 的一个子项目,简单的说,Zookeeper=文件系统+通知机制。它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
我们使用ZooKeeper看重的是它不仅支持集群高可用,还支持持久化节点、临时节点存储和节点变更监控的特点,主要使用了它提供的命名服务、配置管理和集群管理服务。其中,临时节点特性用以实现名字服务注册,节点变更监控实现配置集中管理。
参考:&https://zookeeper.apache.org/
4.RabbitMQ,实现异构通讯服务间的解耦。
Rabbitmq是一种应用程序对应用程序的通信方法,选择RabbitMQ的原因在于它可以支持集群高可用、简单易用、性能出色和完善的管理工具(如:Web ui / Rest API )的特点。
使用Rabbitmq中间件服务端实现解耦,其中主要是利用( Work Queue + Topics Exchange )来实现后端的无缝扩容,并采用Publish/Subscribe + RPC 实现调用解耦,并利用MQ 统一输入输出。
走过的一些坑
最后,总结经验避免犯同样的错,是非常重要的,还有一些技术遗留问题,需要我们自行避开这些坑。以下是我们在构建RPC框架过程中遇到的一些坑:
异步编程效率问题(Fibers)& Node.js 内存泄漏问题
在复杂在构建复杂应用的时候,很多地方都可能发生内存泄露,也需要考虑异步编程效率问题。为解决这两个问题,我们目前主要采取以下三个手段来解决:
a)&框架封装所有网络通信,业务方只关注业务逻辑、提高研发效率;
b)通过Fibers 封装所有异步函数调用转换为同步方法;
c)谨慎选择第三方库。
异步框架中日志跟踪
异步程序记录日志乱序不利于跟踪业务逻辑调用路径。为解决这个问题,我们通过包装 Fibers 对每一个 Fiber 实例进行编号,在所有日志输出中打印 Fiber id 记录异步调用路径,并配合跨模块会话编号实现请求调用跟踪,以此解决日志纪录的无序问题。
RabbitMQ HA 高可用问题
如果需要实现RabbitMQ HA 高可用特性,有两种途径可以实现:Server 端 HA 和 Client HA。Server 端的高可用性可使用 LVS 或 HAProxy来实现,Client 端的高可用性也是一种选择,这样可以减少架构复杂度和层次依赖。值得注意的是,实现高可用特性时,要记得开启Queue 高可用配置。
(/ha.html)
RabbitMQ HA 网络闪断导致节点分区问题
网络不稳定导致RabbitMQ HA 网络闪断,进而导致节点分区问题。针对这个问题,需要添加对 /api/nodes 进行监控,并及时处理分区问题。
具体的解决方法可参考:&/partitions.html
ZooKeeper Session Expired
针对ZooKeeper 会话过期问题,需要大家特别关注处理Zookeeper 集群断开后的重连处理,因为如果重连逻辑没有处理好的话,所有依赖ZooKeeper的特性都将不可用。
具体解决方法可参考:&http://wiki.apache.org/hadoop/ZooKeeper/FAQ
经过应用实践,目前看来 Node.js几乎可以做到其他后端语言所能做到所有的事情,ES6特性正式发布如今有人已经开始高喊&JavaScript: The World's Best Programming Language&,但我也并不认为整个后端完全用Node.js来实现会是一个很好的方案。
本文中提到了Node.js的诸多优点,如异步、非阻塞和事件驱动等,但其也存在一些缺点,如默认单进程单线程不能利用多核,脚本弱类型容易出现运行时BUG,同时因为它简单易用,也导致了代码质量不易控制,对开发人员也提出了更高的要求。所以,就个人经验来看,建议偏复杂业务逻辑控制使用Node.js,如果是偏极致性能的业务建议和C++等其他方案结合使用。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章通过Mesos、Docker和Go,使用300行代码创建一个分布式系统
发表于 11:01|
来源Dzone|
作者John Walter
摘要:虽然Docker和Mesos已成为不折不扣的Buzzwords,但是对于大部分人来说它们仍然是陌生的,下面我们就一起领略Mesos、Docker和Go配合带来的强大破坏力,如何通过300行代码打造一个比特币开采系统。
【编者按】时下,对于大部分IT玩家来说,Docker和Mesos都是熟悉和陌生的:熟悉在于这两个词无疑已成为大家讨论的焦点,而陌生在于这两个技术并未在生产环境得到广泛使用,因此很多人仍然不知道它们究竟有什么优势,或者能干什么。近日,John&Walter在Dzone上撰文,讲述了Mesos、Docker和Go配合带来的强大破坏力,由工程师翻译。以下为译文构建一个分布式系统是很困难的。它需要可扩展性、容错性、高可用性、一致性、可伸缩以及高效。为了达到这些目的,分布式系统需要很多复杂的组件以一种复杂的方式协同工作。例如,Apache&Hadoop在大型集群上并行处理TB级别的数据集时,需要依赖有着高容错的文件系统(HDFS)来达到高吞吐量。在之前,每一个新的分布式系统,例如Hadoop和Cassandra,都需要构建自己的底层架构,包括消息处理、存储、网络、容错性和可伸缩性。庆幸的是,像Apache&Mesos这样的系统,通过给分布式系统的关键构建模块提供类似操作系统的管理服务,简化了构建和管理分布式系统的任务。Mesos抽离了CPU、存储和其它计算资源,因此开发者开发分布式应用程序时能够将整个数据中心集群当做一台巨型机对待。构建在Mesos上的应用程序被称为框架,它们能解决很多问题:Apache&Spark,一种流行的集群式数据分析工具;Chronos,一个类似cron的具有容错性的分布式scheduler,这是两个构建在Mesos上的框架的例子。构建框架可以使用多种语言,包括C++,Go,Python,Java,Haskell和&Scala。在分布式系统用例上,比特币开采就是一个很好的例子。比特币将为生成&acceptable&hash&的挑战转为验证一块事务的可靠性。可能需要几十年,单台笔记本电脑挖一块可能需要花费超过150年。结果是,有许多的“采矿池”允许采矿者将他们的计算资源联合起来以加快挖矿速度。Mesosphere的一个实习生,Derek,写了一个比特币开采框架(/derekchiang/Mesos-Bitcoin-Miner),利用集群资源的优势来做同样的事情。在接下来的内容中,会以他的代码为例。1个Mesos框架有1个scheduler&和1个executor组成。scheduler&和Mesos&master通信并决定运行什么任务,而executor&运行在slaves上面,执行实际任务。大多数的框架实现了自己的scheduler,并使用1个由Mesos提供的标准executors。当然,框架也可以自己定制executor。在这个例子中即会编写定制的scheduler,并使用标准命令执行器(executor)运行包含我们比特币服务的Docker镜像。对这里的scheduler来说,需要运行的有两种任务——one&miner&server&task&and&multiple&miner&worker&tasks。server会和一个比特币采矿池通信,并给每个worker分配blocks。Worker会努力工作,即开采比特币。任务实际上被封装在executor框架中,因此任务运行意味着告诉Mesos&master在其中一个slave上面启动一个executor。由于这里使用的是标准命令执行器(executor),因此可以指定任务是二进制可执行文件、bash脚本或者其他命令。由于Mesos支持Docker,因此在本例中将使用可执行的Docker镜像。Docker是这样一种技术,它允许你将应用程序和它运行时需要的依赖一起打包。为了在Mesos中使用Docker镜像,这里需要在Docker&registry中注册它们的名称:const (
MinerServerDockerImage = "derekchiang/p2pool"
MinerDaemonDockerImage = "derekchiang/cpuminer"
)然后定义一个常量,指定每个任务所需资源:const (
MemPerDaemonTask = 128
// mining shouldn't be memory-intensive
MemPerServerTask = 256
CPUPerServerTask = 1
// a miner server does not use much CPU
)现在定义一个真正的scheduler,对其跟踪,并确保其正确运行需要的状态:type MinerScheduler struct {
// bitcoind RPC credentials
bitcoindAddr string
// mutable state
minerServerRunning
minerServerHostname string
minerServerPort
// the port that miner daemons
// connect to
// unique task ids
tasksLaunched
currentDaemonTaskIDs []*mesos.TaskID
}这个scheduler必须实现下面的接口:type Scheduler interface {
Registered(SchedulerDriver, *mesos.FrameworkID, *mesos.MasterInfo)
Reregistered(SchedulerDriver, *mesos.MasterInfo)
Disconnected(SchedulerDriver)
ResourceOffers(SchedulerDriver, []*mesos.Offer)
OfferRescinded(SchedulerDriver, *mesos.OfferID)
StatusUpdate(SchedulerDriver, *mesos.TaskStatus)
FrameworkMessage(SchedulerDriver, *mesos.ExecutorID,
*mesos.SlaveID, string)
SlaveLost(SchedulerDriver, *mesos.SlaveID)
ExecutorLost(SchedulerDriver, *mesos.ExecutorID, *mesos.SlaveID,
Error(SchedulerDriver, string)
}现在一起看一个回调函数:func (s *MinerScheduler) Registered(_ sched.SchedulerDriver,
frameworkId *mesos.FrameworkID, masterInfo *mesos.MasterInfo) {
ln("Framework registered with Master ", masterInfo)
func (s *MinerScheduler) Reregistered(_ sched.SchedulerDriver,
masterInfo *mesos.MasterInfo) {
ln("Framework Re-Registered with Master ", masterInfo)
func (s *MinerScheduler) Disconnected(sched.SchedulerDriver) {
ln("Framework disconnected with Master")
}Registered在scheduler&成功向Mesos&master注册之后被调用。Reregistered在scheduler&与Mesos&master断开连接并且再次注册时被调用,例如,在master重启的时候。Disconnected在scheduler&与Mesos&master断开连接时被调用。这个在master挂了的时候会发生。目前为止,这里仅仅在回调函数中打印了日志信息,因为对于一个像这样的简单框架,大多数回调函数可以空在那里。然而,下一个回调函数就是每一个框架的核心,必须要认真的编写。ResourceOffers在scheduler&从master那里得到一个offer的时候被调用。每一个offer包含一个集群上可以给框架使用的资源列表。资源通常包括CPU、内存、端口和磁盘。一个框架可以使用它提供的一些资源、所有资源或者一点资源都不给用。针对每一个offer,现在期望聚集所有的提供的资源并决定是否需要发布一个新的server任务或者一个新的worker任务。这里可以向每个offer发送尽可能多的任务以测试最大容量,但是由于开采比特币是依赖CPU的,所以这里每个offer运行一个开采者任务并使用所有可用的CPU资源。for i, offer := range offers {
// … Gather resource being offered and do setup
if !s.minerServerRunning && mems &= MemPerServerTask &&
cpus &= CPUPerServerTask && ports &= 2 {
// … Launch a server task since no server is running and we
// have resources to launch it.
} else if s.minerServerRunning && mems &= MemPerDaemonTask {
// … Launch a miner since a server is running and we have mem
// to launch one.
}针对每个任务都需要创建一个对应的TaskInfo&message&,它包含了运行这个任务需要的信息。s.tasksLaunched++
taskID = &mesos.TaskID {
Value: proto.String("miner-server-" +
strconv.Itoa(s.tasksLaunched)),
}Task&IDs由框架决定,并且每个框架必须是唯一的。containerType := mesos.ContainerInfo_DOCKER
task = &mesos.TaskInfo {
Name: proto.String("task-" + taskID.GetValue()),
TaskId: taskID,
SlaveId: offer.SlaveId,
Container: &mesos.ContainerInfo {
Type: &containerType,
Docker: &mesos.ContainerInfo_DockerInfo {
Image: proto.String(MinerServerDockerImage),
Command: &mandInfo {
Shell: proto.Bool(false),
Arguments: []string {
// these arguments will be passed to run_p2pool.py
"--bitcoind-address", s.bitcoindAddr,
"--p2pool-port", strconv.Itoa(int(p2poolPort)),
"-w", strconv.Itoa(int(workerPort)),
s.rpcUser, s.rpcPass,
Resources: []*mesos.Resource {
util.NewScalarResource("cpus", CPUPerServerTask),
util.NewScalarResource("mem", MemPerServerTask),
}TaskInfo&message指定了一些关于任务的重要元数据信息,它允许Mesos节点运行Docker容器,特别会指定name、task&ID、container&information以及一些需要给容器传递的参数。这里也会指定任务需要的资源。现在TaskInfo已经被构建好,因此任务可以这样运行:driver.LaunchTasks([]*mesos.OfferID{offer.Id}, tasks, &mesos.Filters{RefuseSeconds: proto.Float64(1)})在框架中,需要处理的最后一件事情是当开采者server关闭时会发生什么。这里可以利用StatusUpdate&函数来处理。在一个任务的生命周期中,针对不同的阶段有不同类型的状态更新。对这个框架来说,想要确保的是如果开采者server由于某种原因失败,系统会Kill所有开采者worker以避免浪费资源。这里是相关的代码:if strings.Contains(status.GetTaskId().GetValue(), "server") &&
(status.GetState() == mesos.TaskState_TASK_LOST ||
status.GetState() == mesos.TaskState_TASK_KILLED ||
status.GetState() == mesos.TaskState_TASK_FINISHED ||
status.GetState() == mesos.TaskState_TASK_ERROR ||
status.GetState() == mesos.TaskState_TASK_FAILED) {
s.minerServerRunning = false
// kill all tasks
for _, taskID := range s.currentDaemonTaskIDs {
_, err := driver.KillTask(taskID)
if err != nil {
log.Errorf("Failed to kill task %s", taskID)
s.currentDaemonTaskIDs = make([]*mesos.TaskID, 0)
}万事大吉!通过努力,这里在Apache&Mesos上建立一个正常工作的分布式比特币开采框架,它只用了大约300行GO代码。这证明了使用Mesos&框架的API编写分布式系统是多么快速和简单。原文链接:(责编/仲浩)
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章}

我要回帖

更多关于 分布式数据库搭建 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信