Jokers's Blog

高尚是高尚者的墓志铭 卑鄙是卑鄙者的通行证


  • 首页

  • 分类

  • 归档

  • 标签

停止担心关于Solr和Elasticsearch使用决策

发表于 2019-07-07 | 分类于 BigData |

RE:Stop Worrying about Solr vs Elasticsearch Decisions

有人说Luncene是引擎,Solr和Elasticsearch是车,选择Solr还是ES就像选车。但实际上选择搜索引擎不是选车,它们只是一堆原始的零件、车轮和一个引擎,需要你去组装它。

人们究竟如何使用Solr和ES:

  1. 工程师的配置技巧是决定搜索引擎好坏关键性因素。ES可参考官方配置说明,翻译版在我的博客(http://thathub.com/2018/04/23/bigdata/elastcsearch-config/)

  2. 写插件,扩展搜索引擎的功能

  3. 花费更多的时间在实验上,而不是特定的搜索引擎

我们究竟要比较什么

我们更因该关注的是社区而不是功能。

  • solr来自于Apache Software Foundation (ASF)。ASF希望个人和团体去定义产品的发展方向。Solr使得开发者有更多的机会去深入研究源码。

  • ES是由公司一个公司去主导的。虽然开发者没有主导权,但是对很多人来说,最需要的是”just work”。

GLIB出错

发表于 2019-04-23 | 分类于 Linux |

事故描述

relocation error: /lib64/libc.so.6: symbol _ dl_find_dso_for_object, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference

线上服务器被我玩坏了,紧张的要跑路了。执行所有基本命令都报以上错误。原因是自己手贱改了 /lib64/libc.so.6 的软链。

注意事项

  1. 出现这种问题,千万不要关闭shell,因为除了你现有的shell,没有人能登进来了。
  2. 出于同样的道理,不要重启服务器。

解决方案

# ldconfig (注意是 ‘l‘ 不是 ‘i‘ )

主要功能:在默认搜寻目录/lib和/usr/lib以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如lib.so),进而创建出动态装入程序(ld.so)所需的连接和缓存文件。

感激涕零:
https://www.jianshu.com/p/5ea4e50bf800

MongoDB

发表于 2019-04-01 | 分类于 BigData |

简介

  • MongoDB 是一个面向文档(document-oriented)的数据库。
  • 不再有预定义模式(predefined schema):文档的键(key)和值(value)不再是固定的类型和大小。
  • MongoDB 能自动处理跨集群的数据和负载,自动重新分配文档,以及将用户请求路由到正确的机器上。
  • MongoDB 并不具备一些在关系型数据库中很普遍的功能,如连接(join)和复杂的多行事务(multirow transaction)。省略这些功能是出于架构上的考虑(为了得到更好的扩展性),因为在分布式系统中这两个功能难以高效地实现。
  • MongoDB 把尽可能多的内存用作缓存(cache),试图为每次查询自动选择正确的索引。

基本概念

文档–>行

  • 是键值对的一个有序集

集合–>表

  • 组织集合的一种惯例是使用“.”分隔不同命名空间的子集合。

数据库

  • 多个文档组成集合,而多个集合可以组成数据库。
  • MongoDB 的一个实例可以拥有多个相互独立的数据库(database),每一个数据库都拥有自己的集合。
  • 按照经验,我们将有关一个应用程序的所有数据都存储在同一个数据库中。
  • 把数据库名添加到集合名前,得到集合的完全限定名,即命名空间(namespace)。

安装

sudo yum install mongodb mongodb-server
  • mongod 还会启动一个非常基本的 HTTP 服务器,监听数字比主端口号高 1000 的端口,也就是 28017 端口。这意味着,通过浏览器访问 http://localhost:28017,能获取数据库的管理信息。

  • 启动配置

    sudo vim /etc/mongod.conf
    <!-- 配置后台启动 -->
    fork = true
    
  • 启动
    使用 -f 或 –config 标记,告知服务器使用配置文件

    mongod --config /etc/mongod.conf
    mongod -f /etc/mongod.conf
    

数据类型

MongoDB的文档类似于JSON。JSON只有 null 、布尔、数字、字符串、数组和对象这几种数据类型。没有日期类型。仅有一种数字类型,不能区分浮点数和整数,不能区分32位和64位。没有正则或函数等。MongoDB添加了一些其他类型。

  • null

  • 布尔型 true false

  • 数值
    默认64位浮点型。整型可用NumberInt(4字节带符号整数),NumberLong(8字节带符号整数)。

  • 字符串

  • 日期
    日期被存储为自新纪元以来经过的毫秒数,不存储时区

  • 正则
    语法也与 JavaScript 的正则表达式语法相同

    {"x" : /foobar/i}
    
  • 数组
    数组可包含不同数据类型的元素。

    {"things" : ["pie", 3.14]}
    

    MongoDB 可以查询出 “things” 数组中包含 3.14这个元素的所有文档。要是经常使用这个查询,可以对 “things” 创建索引来提高性能。

    MongoDB 可以使用原子更新对数组内容进行修改,比如深入数组内部将 pie 改为
    pi。

  • 内嵌文档

    {"x" : {"foo" : "bar"}}
    
  • ObjectId
    不同的机器都能用全局唯一的同种方法方便地生成它。在多个服务器上同步自动增加主键值既费力又费时。所以能够在分片环境中生成唯一的标示符非常重要。12字节。

    0 1 2 3  4 5 6  7 8  9 10 11
    时间戳    机器    PID  计数器
    
    {"x" : ObjectId()}
    
  • 自动生成的_id

    如果插入文档时没有 “_ id” 键, 系统 会自动帮你创建一个。 可以由MongoDB 服务器来做这件事,但通常会在客户端由驱动程序完成。这一做法非常好地体现了 MongoDB 的哲学:能交给客户端驱动程序来做的事情就不要交给服务器来做。

  • 二进制数据

  • 代码
    查询和文档中可以包括任意 JavaScript 代码

    {"x" : function() { /* ... * / }}
    

shell

mongo some-host:30000/myDB
<!-- 启动时不连接任何数据库 -->
mongo --nodb
conn = new Mongo("some-host:30000")
db = conn.getDB("myDB")
  • mongo 是一个简化的 JavaScript shell,可以通过查看 JavaScript 的在线文档得到大量帮助。对于 MongoDB 特有的功能,shell 内置了帮助文档,可以使用 help命令查看

    help
    
  • 执行脚本

    <!-- 命令行执行 -->
    mongo script1.js script2.js script3.js
    <!-- 交互执行 -->
    load("script1.js")
    
  • 如果某些脚本会被频繁加载,可以将它们添加到 .mongorc.js 文件中。这个文件会在启动 shell 时自动运行。

  • .mongorc.js 最常见的用途之一是移除那些比较“危险”的 shell 辅助函数。可以在这里集中重写这些方法,比如为dropDatabase 或者 deleteIndexes 等辅助函数添加 no 选项,或者取消它们的定义。

    var no = function() {
        print("Not on my watch.");
    };
    // 禁止删除数据库
    db.dropDatabase = DB.prototype.dropDatabase = no;
    // 禁止删除集合
    DBCollection.prototype.drop = no;
    // 禁止删除索引
    DBCollection.prototype.dropIndex = no;
    
  • 在启动 shell 时指定 –norc 参数,就可以禁止加载 .mongorc.js。

  • 定制shell提示

    prompt = function() {
        return (new Date())+"> ";
    };
    
    prompt = function() {
        if (typeof db == 'undefined') {
            return '(nodb)> ';
        }
        // 检查最后的数据库操作
        try {
            db.runCommand({getLastError:1});
        }
        catch (e) {
            print(e);
        }
        return db+"> ";
    };
    
  • 配置编辑器

    EDITOR="/usr/bin/emacs"
    
  • 编辑变量

    var wap = db.books.findOne({title: "War and Peace"})
    edit wap
    

客户端常用命令

  • 查看db当前指向的数据库

    > db
    test
    
  • 切换数据库

    > use foobar
    switched to db foobar
    

创建、更新和删除文档

插入

db.foo.insert({"bar" : "baz"})
<!-- 批量插入 -->
db.foo.batchInsert([{"_ id" : 0}, {"_ id" : 1}, {"_ id" : 2}])
<!-- 忽略错误并且继续执行添加 continueOnError -->

删除

db.foo.remove()
<!-- 删除 mailing.list 集合中所有 "opt-out" 为true 的人 -->
db.mailing.list.remove({"opt-out" : true})
<!-- drop 直接删除集合会更快 -->
db.tester.drop()

更新

  • 文档替换

    db.people.update({"_ id" : ObjectId("4b2b9f67a1f631733d917a7c")}, joe)
    
  • 使用原子性的修改器,指定对文档中的某些字段进行更新。

  • 要有人访问页面,就增加计数器。

    db.analytics.update({"url" : "www.example.com"}, {"$inc" : {"pageviews" : 1}})、
    
  • “$set” 用来指定一个字段的值。如果这个字段不存在,则创建它。

  • $unset 删除键

    db.users.update({"name" : "joe"}, {"$unset" : {"favorite book" : 1}})
    
  • 增加、修改或删除键时,应该使用 $ 修改器。

  • “$inc” 修改器用来增加已有键的值,或者该键不存在那就创建一个。

  • “$push” 会向已有的数组末尾加入一个元素,要是没有就创建一个新的数组。

  • 使用 “$each” 子操作符,可以通过一次 “$push” 操作添加多个值。

  • 可以将 “$slice” 和 “$push” 组合在一起
    使用,这样就可以保证数组不会超出设定好的最大长度

  • 可以在清理元素之前使用 “$sort”,只要向数组中添加子对象就需要清理:

    db.movies.find({"genre" : "horror"},{"$push" : {"top10" : {"$each" : [{"name" : "Nightmare on Elm Street", "rating" : 6.6},{"name" : "Saw", "rating" : 4.3}],"$slice" : -10,"$sort" : {"rating" : -1}}}})
    
  • 不能只将 “$slice” 或者 “$sort” 与 “$push” 配合使用,且必须使用 “$each”。

  • 将数组作为set使用

    db.users.update({"_ id" : ObjectId("4b2d75476cc613d5ee930164")},{"$addToSet" : {"emails" : "joe@gmail.com"}})
    
  • {“$pop”:{“key”:1}} 从数组末尾删除一个元素,{“$pop”:{“key”:-1}} 则从头部删除。需要基于特定条件来删除元素,”$pull”。

    db.lists.update({}, {"$pull" : {"todo" : "laundry"}})
    
  • MongoDB 提供了定位操作符 “$”,用来定位查询文档已经匹配的数组元素,并进行更新。

upsert

  • 使用 upsert,既可以避免竞态问题,又可以缩减代码量(update 的第 3 个参数表示这是个 upsert)

    db.analytics.update({"url" : "/blog"}, {"$inc" : {"pageviews" : 1}}, true)
    
  • “$setOnInsert” 只会在文档插入时设置字段的值。

  • save 是一个 shell 函数,如果文档不存在,它会自动创建文档;如果文档存在,它就更新这个文档。

  • 要更新所有匹配的文档,可以将 update 的第 4 个参数设置为 true。

  • 运行 getLastError 命令(可以理
    解为“返回最后一次操作的相关信息”)。键 “n” 的值就是被更新文档的数量。

  • 调用 getLastError 仅能获得关于更新的有限信息,并不能返回被更新的文档。可以通过 findAndModify 命令得到被更新的文档。这对于操作队列以及执行其他需要进行原子性取值和赋值的操作来说,十分方便。

查询

find

  • 指定需要返回的键

    db.users.find({}, {"username" : 1, "email" : 1})
    <!-- 剔除 -->
    db.users.find({}, {"fatal_weakness" : 0})
    
  • “$lt”、”$lte”、”$gt” 和 “$gte” 就是全部的比较操作符,分别对应 <、<=、> 和 >=

  • “$ne”表示“不相等”

    db.users.find({"username" : {"$ne" : "joe"}})
    
  • or

    db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}})
    db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}})
    db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]})
    
  • not
    “$mod” 会将查询的值除以第一个给定值,若余数等于第二个给定值则匹配成功

    db.users.find({"id_num" : {"$mod" : [5, 1]}})
    db.users.find({"id_num" : {"$not" : {"$mod" : [5, 1]}}})
    
  • 条件语句
    注意,查询优化器不会对 “$and” 进行优化,这与其他操作符不同。

    db.users.find({"$and" : [{"x" : {"$lt" : 1}}, {"x" : 4}]})
    

索引

唯一索引

  • 复合唯一索引创建

    db.users.ensureIndex({"username" : 1, "age" : 1}, {"unique" : true})
    
  • 在已存在集合创建唯一索引,去除重复值

    db.people.ensureIndex({"username" : 1}, {"unique" : true, "dropDups" : true})
    

稀疏索引

唯一索引会把null当作一个值,稀疏索引可以避免这种情况

db.foo.ensureIndex({"email" : 1}, {"unique" : true, "sparse" : true})

索引管理

  • 查看指定集合的索引信息

    db.foo.getIndexes()
    

mongoimport

支持JSON,CSV,TSV,CSV格式delimiter仅支持”,”和”\t”

  • –fields 指定字段名字和类型

  • 示例

    <!-- --upsert insert or update objects that already exist -->
    <!-- --jsonArray load a json array, not one item per line. -->
    mongoimport --db db --collection foo --file f.json
    

Sqoop

发表于 2019-02-26 | 分类于 BigData |

MapReduce需要使用额外的API与存储在HDFS外的数据交互。例如,数据经常存储在RDBMS,开源的工具Sqoop允许用户将结构化数据提取到Hadoop,使用MapReduce处理或者更高级的工具(例如hive)。Sqoop可以将处理的最终结果导出到RDBMS。

Getting Sqoop

列出Sqoop所有的工具
% sqoop help

列出具体工具的使用说明
% sqoop help import

Sqoop Connectors

Sqoop connector是一个模块化的组件,使得Sqoop可以将数据导入或导出到其它数据库(MySQL, PostgreSQL, Oracle, SQL Server, DB2, and Netezza)。如果数据库支持JDBC协议,可以使用通用的JDBC connector。Sqoop提供优化(MySQL, PostgreSQL, Oracle, and Netezza)后的connector,使用数据库定义的API,执行批量数据传输效率更高。

A Sample Import

我们先下载MySQL的JDBC driver JAR文件,放到Sqoop的lib目录下。
将数据表导入到HDFS
% sqoop import –connect jdbc:mysql://localhost/mydatabase –table mytable -m 1
sqoop的导入工具将运行一个MapReduce工作,连接数据库并读表。默认开启4个map并行任务加快导入速度。每个任务导入到不同的文件,但是都在同一个目录下。(-m 1)指定单独的map任务。
检查导入的文件:
% hadoop fs -cat widgets/part-m-00000
Sqoop默认导入逗号分割的文本文件,分割符可以明确指定,以及允许字段内容存在分割符的字段封闭符和转义符。

Imports: A Deeper Look

分割数据到多个map任务可以提高导入性能,Sqoop通常会选择主键作为分割依据。
假设有100.000行数据,id为0-99.999,5个map分别执行查询:
SELECT id, widget_name, … FROM widgets WHERE id >= 0 AND id < 20000 ,
SELECT id, widget_name, … FROM widgets WHERE id >= 20000 AND id < 40000 ,
and so on.
如果id非均匀分布,一些map会有很少甚至没有导入工作。用户可以指定字段作为分割依据(via the –split-by argument)。

Controlling the Import

Sqoop不需要每次导入全部数据,可以导入表的子集,通过 –where 参数。
指定 –query参数,可以执行更多的控制。

Incremental Imports

增量导入很常见,为了识别新数据,–check-column指定字段,–last-value指定值大于的数值。
这种方法适合新增而没有更新的情况,称为append模式。通过–incremental append激活。如果某一列记录最后更新时间,可以基于时间进行增量导入,通过–incremental lastmodified激活。
增量导入以后,Sqoop将打印出作为下次使用的last-value。手工导入时很有用,但是定期导入最好使用Sqoop的saved job工具,自动保存last value并用于下次job。sqoop job –hlep

Direct-Mode Imports

Sqoop有很多测律执行导入。有些数据库提供更快提取数据的工具,例如MySQL的mysqldump,这些工具的使用称为direct mode(via the –direct argument)。但是MySQL的direct mode不能处理大的对象,例如CLOB或者BLOB字段,所以Sqoop需要JDBC加载这些字段。因此direct mode不能像JDBC一样实现通用的目的。

hadoop2指南

发表于 2019-01-31 | 分类于 BigData |

Hadoop Fundamentals

Chapter 1. Meet Hadoop

Hadoop通常指大型的生态系统,不仅仅是HDFS和MapReduce,属于分布式计算和大规模数据处理
例如,HBase,key-value存储方式,使用HDFS作为底层存储
yarn,Hadoop中新处理模型的推动者,它是一个集群资源管理系统,它允许分布式程序(不仅仅是MapReduce)在Hadoop集群处理数据
Hive,大数据集合低延迟的SQL交互查询
Spark,许多算法,例如机器学习算法,本质上是在数据集上的迭代计算,而MapReduce并不支持迭代数据持久化到内存,需要每次在磁盘载入,而Spark不需要
Solr,可在Hadoop集群上运行,索引文档存储在HDFS并提供查询服务
MapReduce有助于理解一些通用概念,例如输入格式概念和数据集的分片等
MapReduce等Hadoop处理模型都是随着数据量线性扩展的,而功能函数(例如Map和Reduce)可以在分区并行工作,因此假设据数量翻倍,而集群节点数量也翻倍,那么计算时间是不变的

Chapter 2. MapReduce

A Weather Dataset

我们以计算历年记录的最高温度为例,传统方法会逐行读取并比较获得最高温度。为了提高运行速度,可以使用并行处理。
1.我们可以使用不同的进程运行不同年份的记录,但是不同年份的数据量不同,计算时间取决于最大的文件。因此最好的办法是把输入的数据分割成大小相等的块再分别处理。
2.因为数据被分割成大小相等的块,每个数据块都会计算出不同年份的最大温度,最终我们还要找到每年的最大温度。
3.仍然会受限于单台计算机的处理能力,可以使用多台计算机,那么主要问题在与协调性和可靠性,哪台计算机执行全局的任务,如何处理失败的进程。
以上方法虽然可行但是繁杂,所以我们可以借助类似Hadoop的框架。

Analyzing the Data with Hadoop

MapReduce将操作分为两个阶段,map阶段和reduce阶段,每个阶段都是key-value对作为输入和输出,同时需要编写map和reduce方法。
map阶段的输入是NCDC原始的行数据,key是每行相对应文本开始位置的偏移值,不过可以忽略。map方法只是数据准备,只需要在每行数据中提取出年份和温度。
可视化map的工作
输入数据:
0067011990999991950051507004…9999999N9+00001+99999999999…
0043011990999991950051512004…9999999N9+00221+99999999999…
0043011990999991950051518004…9999999N9-00111+99999999999…
0043012650999991949032412004…0500001N9+01111+99999999999…
0043012650999991949032418004…0500001N9+00781+99999999999…
呈现给map方法的key-value对:
(0, 0067011990999991950051507004…9999999N9+00001+99999999999…)
(106, 0043011990999991950051512004…9999999N9+00221+99999999999…)
(212, 0043011990999991950051518004…9999999N9-00111+99999999999…)
(318, 0043012650999991949032412004…0500001N9+01111+99999999999…)
(424, 0043012650999991949032418004…0500001N9+00781+99999999999…)
map提取年份和温度,并输出:
(1950, 0)
(1950, 22)
(1950, -11)
(1949, 111)
(1949, 78)
MapReduce框架通过key聚合排序map的输出,再传输给reduce,所以reduce的输入为:
(1949, [111, 78])
(1950, [0, 22, −11])
reduce遍历list并找出最大温度:
(1949, 111)
(1950, 22)

Scaling Out

将数据储存在分布式文件系统,使用Hadoop的资源管理系统(YARN),可使得每台机器持有一部分数据进行MapReduce计算。

Data Flow

YARN分配任务到集群节点,如果一个任务失败,会被自动分配到其它节点。Hadoop将输入数据分片并创建map任务将分片作为输入数据。
分片越小,负载均衡越好,因为一个运行速度快的机器可以处理更多的分片。
但是如果分片太小,分片的管理和map任务的创建会耗费太多的时间。分片大小最好等于HDFS的block,默认是128M。数据存在于执行map任务的节点,执行效率更高,因为节省了宝贵的集群间的带宽资源。
一个block大小的分片是可以保证存储在同一个节点的,这就是为什么最优分片大小是block size。假设分片大小是两个block size,执行map任务的节点可能没有恰好存储两个block,这就需要在节点间传输数据。
reduce任务数量可以自定义,map的输出需要通过网络传输合并传递给运行reduce的节点,reduce的输出通常存储在HDFS。
当有多个reduce时,map分割输出,相同的key必须在同一个分割,用户可以自定义分割,但是默认分割方法挺好的,

Combiner Functions

许多MapReduce任务受限于集群的可用带宽,所以研究如何最小化map和reduce间传递的数据变得很重要。combiner方法允许用户指定并作用于map的输出,最后形成reduce的输入。因为combiner方法是优化方法,hadoop不保证可以运行几次combiner。
第一个map输出:
(1950, 0)
(1950, 20)
(1950, 10)
第二个输出:
(1950, 25)
(1950, 15)
reduce输入:
(1950, [0, 20, 10, 25, 15])
reduce输出:
(1950, 25)
我们可以使用combiner方法,类似于reduce,找到每个map输出的最大值:
(1950, [20, 25])
可表示为:
max(0, 20, 10, 25, 15) = max(max(0, 20, 10), max(25, 15)) = max(20, 25) = 25
但是,如果计算平均值,不能使用mean作为combiner,因为:
mean(0, 20, 10, 25, 15) = 14
但是:
mean(mean(0, 20, 10), mean(25, 15)) = mean(10, 20) = 15
综上,combiner可以减少传输数据的数量,值得考虑是否可以用combiner。

Chapter 3. The Hadoop Distributed Filesystem

The Design of HDFS

HDFS is a filesystem designed for storing very large files with streaming data access
patterns, running on clusters of commodity hardware.

Very large files
文件大小数百M,G,T,P

Streaming data access
HDFS建立在最有效的数据处理模式下,一次写入,多次读取的模式。因此读取整个数据集的时间比读取第一条数据的延迟时间更重要。

Commodity hardware
Hadoop不需要昂贵,高可靠性的硬件。

Low-latency data access
HDFS对几十毫秒内的低延迟访问表现不好,因为它主要优化方向是高吞吐量,势必造成高延迟。HBase是当前达到低延迟的选择。

Lots of small files
namenode将文件系统元数据放在内存,而每个文件,目录,block占用大约150比特。假设有100万的文件,每个文件是一个block,需要300M内存。

Multiple writers, arbitrary file modifications
目前仅支持单用户在文件末尾append

HDFS Concepts

Blocks

每个block默认128M,文件被拆分成block大小,不足block大小的文件虽然是一个block,但是仅占用实际大小的空间。
block带给分布式系统好处:

  1. 文件大小可以大于单个结点的磁盘
  2. 简化储存子系统
  3. 适合复制,增加了系统容错能力,默认复制到3个结点
Namenodes and Datanodes

HDFS集群是master−worke模式,一个namenode(master)和一些datanode(workers)。namenode管理文件系统命名空间。它包含文件系统树和所有文件及目录的元数据,这些数据持久化在本地磁盘,两个文件分别是namespace image和edit log。namenode不持久化block的位置,因为每次系统启动都会通过datanode重建位置信息。
客户端访问namenode和datanode,对用户来说是透明的。
datanode存储检索block并周期性的向namenode报告blocks的存储情况。
没有namenode,HDFS将无法工作。namenode故障将使得文件系统的文件丢失,为了避免这种情况,Hadoop提供了两种机制:
第一种是备份文件系统元数据,备份是同步的和原子的,通常的配置是写入本地磁盘和原称NFS mount。
第二种是运行secondary namenode,周期性的合并namespace image及edit log。secondary namenode常运行在单独的机器,因为它需要大量的CPU和内存执行merge。如果主namenode挂了,总会出现数据丢失,在这种情况通常从NFS复制一份namenode的元数据到ssecondary namenode并将其作为namenode使用。

Block Caching

通常datanode从disk读block,但是对高频访问的block可以明确缓存到datanode的内存,可以增加读的效率。应用通过添加缓存指令到缓存池来指导namenode缓存文件。

HDFS Federation

每个文件和块的引用是保存在namenode的内存中的,我们可以添加namenode去扩展,每个namenode管理一部分的namespace,相互对立,不影响其它namenode的可用性

HDFS High Availability

secondary namenode元数据并使用辅助namenode防止数据丢失,不能获得高可用的系统。
如果namenode挂掉,新的namenode需要载入namespace image到内存,重现edit log,接收所有datanode上报的block映射关系,才能正常运行。在大型集群,需要耗费30分钟甚至更长的时间。
Hadoop 2添加高可用性(HA)支持,使用一对namenode(active-standby),active namenode挂掉,standby可以很快提供服务。
架构需要做一些改动:

  • namenode必须使用高可用性共享存储来共享编辑日志
  • datanode必须向所以namenode发送block的映射信息
  • 客户端需要配置处理故障转移,对用户透明

The Command-Line Interface

首先安装一个伪分布式的Hadoop,配置文件中的fs.defaultFS设置为hdfs://localhost/,使用HDFS作为Hadoop的文件系统。
dfs.replication设置为1(默认3),不对blocks进行复制。
获得帮助信息

hadoop fs -help 

从本地文件系统复制文件到HDFS

% hadoop fs -copyFromLocal input/docs/quangle.txt \
hdfs://localhost/user/tom/quangle.txt

我们可以省略schema和host,使用定义在core-site.xml中的值

% hadoop fs -copyFromLocal input/docs/quangle.txt /user/tom/quangle.txt

创建文件夹以及列出所有的文件

% hadoop fs -mkdir books
% hadoop fs -ls .

Hadoop Filesystems

Hadoop有许多种Filesystems

Interfaces

接口有Java的Native API
有HTTP REST API,通过HTTP访问HDFS有两种方式:
1、直接访问namenode,然后重定向到datanode
2、使用代理服务器,代理负责访问namenode和重定向到datanode,这中方式可以允许更严格的防火墙和带宽限制策略
HTTP接口速度比Native慢

Parallel Copying with distcp

并行复制数据,可以有效代替 hadoop fs -cp
复制一个文件

% hadoop distcp file1 file2

复制目录

% hadoop distcp dir1 dir2

如果dir2不存在,则新建dir2并且把dir1的数据拷贝到dir2。如果dir2存在,则dir1会复制到dir2/dir1。
使用 -overwrite 选项可以避免改变目录结构。
使用 -update 选项只同步更新。

% hadoop distcp -update dir1 dir2

distcp使用MapReduce任务实现,并行的maps执行复制,没有reduce。多达20个maps执行复制,可以通过 -m 参数指定数量。
distcp通常用于两个集群间传递数据

% hadoop distcp -update -delete -p hdfs://namenode1/foo hdfs://namenode2/foo

–delete 删除namenode1不存在的文件,-p 保存文件参数,例如,block大小、权限等。
如果两个集群HDFS版本不同,可以使用webhdfs协议

% hadoop distcp webhdfs://namenode1:50070/foo webhdfs://namenode2:50070/foo
Keeping an HDFS Cluster Balanced

为保证集群中每个结点的blocks数量平衡,建议使用默认的20个map执行distcp,因为如果只有一个map,那么所有复制的block都会在运行map的node建立一个副本。

Chapter 4. YARN

YARN是在Hadoop2引入的,改善MapReduce的实现,并且支持其他分布式计算框架。

Appium + mumu 手机自动化测试环境和爬虫

发表于 2019-01-10 | 分类于 Spider |

简介

不论是手机端自动化测试还是爬虫都需要用到Appium和手机模拟器,这里用的mumu,没有使用官方的AVD(Android Virtual Devices)或者Genymotion。
mumu安装很简单,就不再介绍了。
Appium是selenium的封装,并提供移动设备相关指令。Appium是跨平台的C/S应用。Appium可以通过NPM安装或下载桌面版。

安装SDK

  • 下载SDK Manager,安装对应版本的SDK。
  • platform-tools和tools路径添加环境变量,需要用到adb(Android Debug Bridge)命令行工具

    <!-- 测试环境变量是否配置成功 -->
    adb devices
    

adb连接mumu

  • 查看mumu配置文件(emulator\nemu\vms\myandrovm_vbox86\myandrovm_vbox86.nemu)的ADB_PORT,确定端口号(默认7555)
  • 连接

    adb connect 127.0.0.1:7555
    
  • 查看deviceName

    adb devices
    
  • mumu“设置”–>”关于平板电脑”查看platformVersion

  • 获取需要启动及控制的APP信息(appPackage–package name appActivity–launchable-activity name),android-sdk\build-tools\28.0.3\aapt.exe

    aapt dump badging yourAPP.apk
    

Python实现示例,模拟打开APP

desired_caps = {
            'platformName': 'Android',
            'deviceName': '127.0.0.1:7555',
            'platformVersion': '6.0.1',
            'appPackage': 'com.lawyee.wenshuapp',
            'appActivity': 'com.lawyee.wenshuapp.ui.SplashActivity'
        }
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

Proxy server

发表于 2018-12-12 | 分类于 Tools |

Squid

安装

yum install squid

配置 /etc/squid/squid.conf

# 允许所有主机访问,添加如下
acl all src all
http_access allow all

# 隐藏真实IP,添加如下
forwarded_for delete
or
forwarded_for off

启动,退出

service squid start
service squid stop
service squid restart

测试

curl -x http://host:port -L http://www.baidu.com

Authentication

  • INSTALL httpd-tools

    yum -y install httpd-tools
    
  • CREATE A USERNAME/PASSWORD

    touch /etc/squid/passwd && chown squid /etc/squid/passwd
    htpasswd /etc/squid/passwd pxuser
    
  • CONFIG

    注意配置添加的位置和顺序
    #
    # INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
    #
    auth_param basic program /usr/lib64/squid/ncsa_auth /etc/squid/passwd
    auth_param basic children 5
    auth_param basic realm Squid proxy-caching web server
    auth_param basic credentialsttl 2 hours
    auth_param basic casesensitive off
    
    acl zcb proxy_auth REQUIRED
    http_access allow zcb
    
  • TEST

    curl -x http://host:port --proxy-user username:pass -L http://www.baidu.com
    

Tinyproxy

Privoxy

Shadowsocks

server 安装

pip install shadowsocks

配置

# 新建文件 /etc/shadowsocks.json

{
    "server":"0.0.0.0",
    "server_port":8888,
    "local_address": "127.0.0.1",
    "local_port":1080,
    "password":"mypassword",
    "timeout":300,
    "method":"aes-256-cfb",
    "fast_open": false
}

多用户配置,配置多个端口

"port_password":
{
    "20000": "password0",
    "20001": "password1",
    "20002": "password2",
}
"_comment":
{
    "20000": "userA",
    "20001": "userB",
    "20002": "userC",
}

运行,退出

ssserver -c /etc/shadowsocks.json -d start
ssserver -c /etc/shadowsocks.json -d stop

VIM

发表于 2018-12-05 | 分类于 Tools |

配色

  • 在~目录新建文件

    $ vi ~/.vimrc
    
  • 添加

    # 显示行号
    set nu
    # 设置配色
    colorscheme desert
    

行号显示开启和关闭

:set nonumber
:set number

选择 复制 粘贴 剪切

  • 按键v进入 visual 模式

    • j/k/h/l —— 文本选择
    • d —— 剪切
    • y —— 复制
    • p —— 粘贴
    • ^ —— 选中当前行,光标位置到行首(或者使用键盘的HOME键)
    • $ —— 选中当前行,光标位置到行尾(或者使用键盘的END键)
  • V 进入 Visual Line 模式

    • j/k —— 文本选择
  • Ctrl + V 进入 Visual Block 模式

    • j/k/h/l —— 选中文本块
    • Shift + i —— 块模式下的插入
    • ESC —— 完成多行的插入

回退 撤销

  • u —— 撤销上一步的操作
  • Ctrl+r —— 恢复上一步被撤销的操作

浏览位置移动

  • Ctrl-O —— 后退
  • Ctrl-I —— 前进

差找

在normal模式下按下/即可进入查找模式,输入要查找的字符串并按下回车。 Vim会跳转到第一个匹配。按下n查找下一个,按下N查找上一个。

取消高亮

:nohl

SVN

发表于 2018-12-05 | 分类于 Tools |

Ignore Directory

  • vim ignore.txt

    dirname
    
  • Ignore

    svn propset svn:ignore -F ignore.txt .
    
  • If the directory is already “in” svn.

    svn rm --keep-local dirname
    

PyTorch VS TensorFlow

发表于 2018-11-16 | 分类于 ML |

原作者: Iliya Valchanov
转载自: quora

Let’s start from NumPy (you’ll see why a bit later).

You can build a machine learning algorithm even with NumPy, but creating a deep neural network is getting exponentially harder. NumPy is designed for (fast) computations, and not machine learning. It is usually used for machine learning together with a machine learning package.

PyTorch

PyTorch is similar to NumPy in the way that it manages computations, but has a strong GPU support. Similarly to NumPy, it also has a C (the programming language) backend, so they are both much faster than native Python libraries. NumPy could be GPU accelerated (with some extra code), but it doesn’t have this strong GPU support that PyTorch or TensorFlow do. Finally, PyTorch was specifically tailored for GPU functionality in Python.

TensorFlow

TensorFlow, on the other hand, was written mainly in C++ and CUDA (NVIDIA’s language for programming GPUs), and was not specifically created for Python. It provides functionalities in C, C++, Java, Go (Google’s language), and there is community support for Haskell and Rust [1]. So, with TF, you are not restricted by Python. Even if the syntax differs a bit across languages, the concepts are the same.

Comparison

Now, PyTorch has deep neural networks functionalities and that is why it is often compared with TensorFlow, sklearn, etc. Moreover, TensorFlow has a peculiar logic (with concepts like placeholders, sessions, etc.). So, for TensorFlow, you need to make that extra effort. Knowing NumPy (which is my underlying assumption for the dear reader), it is easier to switch to PyTorch than TensorFlow, that is why it is gaining popularity so fast.

As TensorFlow was used by Google for so long, it is very easy to deploy algorithms using it. So you can think about it as more product oriented. Logically, you want to be able to deploy the algorithms that you are creating (you can check out TensorFlow Serving[2] for more on that).

PyTorch, on the other hand, is more recent, so it does not have the full range of capabilities of other packages. I am sure that this will change and they are on their way to catch up. However, TensorFlow has this module tf.contrib. That’s code, contributed by the community, that will probably be embedded into the core TF. Point being, the TensorFlow community is stronger, because TF is older. I don’t know if PyTorch will catch up to the community of TF (that depends on the users and the adoption).

Opinion

So, my verdict would be that TensorFlow has kind of stood the test of time (if you can use this expression for a framework that is not that old itself) and is still more widely adopted. It has more capabilities and a better scalability for larger projects (projects of the scale of Google). PyTorch is surely gaining momentum as it is easier to learn but doesn’t have the same integration. It is very good for small projects that need to be done quite fast, but is not optimal for product deployment.

Practical reasons to learn both

If you want to work in the industry, it is probable that a company may have some customized framework. On your CV, you will be expected to have experience with (a) machine learning package(s). In any case, they won’t expect you to have worked with all of them. If you have to choose a single one of them, it seems to me that going for “the easier to learn” package looks worse. So learn both or go with TF.

123…5
Jokers

Jokers

hlxstc680@gmail.com

49 日志
13 分类
6 标签
© 2019 Jokers
由 Hexo 强力驱动
主题 - NexT.Muse