Redis vs Memcached?

Redis Memcached
网络IO模型 单线程的IO复用的网络模型 多线程的非阻塞IO复用的网络模型
支持的数据结构 key-value数据类型,还支持list、set、zset、hash等 key-value形式存储和访问数据
内存管理机制 现场申请内存 预分配的内存池
数据存储及持久化 in-memory、支持持久化:快照、AOF in-memory,不支持持久化
虚拟内存 物理内存用完时,可利用虚拟内存(不建议开启,开销大) 物理内存用完时,LRU替换掉不常用的缓存
数据一致性 提供事务,保证命令的原子性,中间不会被任何操作打断 提供了cas命令,保证多个并发访问操作同一份数据的一致性
集群管理 服务器端构建分布式存储 只能采用客户端实现分布式存储,比如在客户端用一致性哈希
性能 单核,数据量<10w 时高,数据量>10w时低 多核,数据量<10w时低,数据量>10w时高

在纯Key/Value应用场景(例如缓存),数据量非常大并且并发量非常大,Memcached拥有更高的读写性能;首先在内存分配机制上,Memcached使用预分配内存可以减少内存分配时间,Redis临时申请空间可能导致碎片。所以Memcached会快一些。其次在VM方面,Memcached把所有数据都放在物理内存,Redis有自己的VM机制,数据超量的时候会引发swap把冷数据刷到磁盘上。所以数据量大时Memcached会快一点。然后在网络模型上,Redis和Memcached都是使用非阻塞IO复用模型,但Redis还提供一些排序、聚合功能,复杂的计算会阻塞整个IO调度。最后在线程模型上,Memcached是多线程,主线程监听,worker子线程接收请求,执行读写,过程中可能有锁冲突。Redis是单线程,虽然无锁但是不能利用多核CPU的优势。

在数据持久化方面redis有更强大的功能。但是redis的快照不能保证数据不丢失,AOF会降低效率并且不能支持太大的数据量。如果只是缓存场景,那么开启固化可以在重启的时候有预热的数据不会导致数据库瞬间压力过大,但是可能会导致一些数据不一致,所以只能在允许一些数据不一致或者只读场景下使用。

在数据同步场景,Redis拥有更为丰富的数据类型(哈希、列表、集合、有序集合)。

《如何在工作中快速成长》读后感

原文链接:https://mp.weixin.qq.com/s/wqb_Vwv-r6Aj-LEm_EWJXQ

观点提炼:

  1. 思考脑与反射脑
    • 人的行为5%是非习惯性,运用逻辑思考。95%是习惯性,运用反射脑的直觉驱动;
    • 把95%的低质量习惯反射,训练成高质量的反射。提升自己的直觉准确性;
    • 习惯输入:一字不差的阅读。习惯输出:用ppt做分享。
  2. 习以为常
    • 在触发条件发生进入下一个行为时,让自己作对选择题。
  3. 时间管理:三八理论
    • 找到不被打扰的时间用于投资自己的成长
      • 睡前抽出40分钟,早上抽出一个半小时,晨会前抽出30分钟
  4. 最重要的财富:注意力
    • 专注在目标事务上,直到产出预期的结果
      • 只字不差阅读
      • 边读边做笔记
      • 读完写ppt分享
  5. 拿结果手段:执行力
    • 想明白,然后一步一步做下去
      • 我知道未来三个月我要以专家思维学习这门领域知识
      • 我知道今天早上五点半起床,在不被打扰的情况下学习第一章
      • 我知道已经学习一周,需要利用笔记做好反思和总结
      • 我知道学习快结束需要使用ppt或写作来分享观点
  6. 贵人
    • 可以陪你持续输出高质量的人
    • 自我稳定性:自我的容器变得大了,可以容忍对方的批判和情绪
    • 自我灵活性:在接受批判后调整自己的状态,让自己变好
    • 自我疆界:自我调整后,看事物的角度变了,能力提升了,自我疆界在扩张
    • 自我组织力:当一个人在高压下感觉要散架了,或者被击溃而瓦解的时候能够自我重组
  7. 会议
    • 参与者:认真聆听,快速提炼自己想表达的逻辑
    • 聆听者:在脑中组织输入
    • 中断者:有些会议确实到了需要中断的时候
  8. 跳出舒适区
    • 进入学习区,平衡挑战和技能,达到心流体验(调动自己最高水平的技能,再努力一点点,刚好能解决问题)
  9. 职业规划
    • 职业规划应该是需要获得什么能力:拿结果能力、一杠到底、专业技能、系统性思维
  10. 时间换空间
    • 每天在不被打扰的时间中投资自己,通过不断输出确认不足,弥补不足。把自己逼近成长临界点,跨过去。反复循环

nvidia-k8s-device-plugin源码解析

Kubernetes 提供了Device Plugin 的机制,用于异构设备的管理场景。原理是会为每个特殊节点上启动一个针对某个设备的DevicePlugin pod, 这个pod需要启动grpc服务, 给kubelet提供一系列接口。DevicePlugin 注册一个 socket 文件到 /var/lib/kubelet/device-plugins/ 目录下,kubelet 通过这个目录下的socket文件向对应的 Device plugin 发送grpc请求。

具体流程如下:

  • nvidia-container-runtime-hook :安装该hook,把docker的default-runtime修改为nvidia-container-runtime-hook。这个hook会在创建容器前先hook住,检查是否需要GPU(通过检查是否有NVIDIA_VISIBLE_DEVICES ),如果需要则调用libnvidia-container暴露GPU,把设备和驱动mount到容器内。
  • K8s通过device-plugin
    • 上报节点GPU数量
    • 分配GPU:把GPU需求转换为NVIDIA_VISIBLE_DEVICES注入容器,并将设备和驱动映射到容器中

 

参考:https://www.twblogs.net/a/5bde55f42b717720b51be0c4

https://my.oschina.net/jxcdwangtao/blog/1797047

https://blog.csdn.net/s812289480/article/details/83588320

缓存架构的实现

缓存架构的实现需要解决的最主要的问题就是如何更新缓存,具体有由业务方更新和由后台线程更新两种方式:

  1. 业务方更新:业务方请求不到缓存数据之后,去存储系统中获取并生成缓存数据。这里需要解决的一个问题是如果多个业务方同时遇到缓存失效的问题,那么所有业务方都会请求存储系统并更新缓存,这样会对业务系统和缓存都造成很大的压力。这时候需要有个分布式锁,保证只有一个线程能进行缓存更新,未获取锁的线程要不就等锁释放后重新读取缓存,要不就返回空值。
  2. 后台线程更新:缓存时效设置为永久,由后台线程去更新缓存。这里需要解决的问题是有一些key会被踢出缓存系统的情况。这里可以有两种处理方式,第一种是后台线程频繁的读取缓存,把被踢出的key再加入缓存;一种是业务方获取不到key之后,打一个获取不到的消息到消息队列中,后台线程从消息队列中得到通知,更新缓存。更新前需要检查key是否存在,因为有可能有很多个业务方同时都获取不到key。

faiss索引调研(四)——faiss源码分析

https://zhuanlan.zhihu.com/c_159623040

1. faiss最大堆实现

和普通最大堆没什么区别。

pop:堆顶元素出列(放到最后一个位置,最后一个位置后面会置为无效),然后循环把子节点往上提(提上来大的那个子节点(左vs右))。

push:先放到最后一个位置,然后循环往上找到应该插入的位置,每次往上一步就把被对比的堆里面的原元素往下踢一个位。

2. faiss暴力搜索(找当前元素的最相近的k个元素)

循环遍历数组,建立最大堆。

亮点是计算距离的时候使用的是分段计算,把一个d维向量分开每一段计算距离。

3. faiss聚类

  1. 先随机初始化k个聚类中心;
  2. 用暴搜(用上面的方法)找出数组中每个向量所属的聚类中心。把聚类中心的向量求和并求均值作为新的聚类中心,对于空元素的聚类中心,找到另一个分裂中心拿来分裂;
  3. 循环步骤2知道达到迭代次数。

4. faiss倒排

索引:先聚类,然后遍历每个向量找到最近的1个聚类中心,把聚类中心的id和向量放到list中作为倒排表(ids和codes)。

搜索

  1. 粗查询:返回最近的nprobe个聚类中心以及对应的距离;
  2. 查询倒排表:对于当前查询向量的每个聚类中心:拉取聚类中心的倒排list,遍历list中的每个向量,和查询向量一一计算距离,将结果放入返回的最大堆

faiss索引调研(三)——faiss分析

一、简介

faiss是FaceBook 2017年开源的一个用于高效相似性搜索和密集向量聚类的库,能对海量数据进行高效的相似问搜索和密集向量聚类。

http://houjie13.com/articles/2018/06/21/1529587425820.html

http://houjie13.com/articles/2018/06/25/1529933223485.html

faiss的faq:https://github.com/facebookresearch/faiss/wiki/Troubleshooting#slow-brute-force-search-with-openblas

多线程的限制:https://github.com/facebookresearch/faiss/wiki/Threads-and-asynchronous-calls#performance-of-search

faiss里面几种索引的简介:https://zhuanlan.zhihu.com/c_159623040

faiss源码剖析https://blog.csdn.net/dramer110/article/details/84001605

二、安装

  1. 安装openblas(一个矩阵运算库)
    • yum install gcc-gfortran
      git clone https://github.com/xianyi/OpenBLAS.git
      cd OpenBLAS
      make FC=gfortran
      make install (openblas安装到/opt/下面)
      ln -s /opt/OpenBLAS/lib/libopenblas.so /usr/lib/libblas.so.3
      ln -s /opt/OpenBLAS/lib/liblapack.so.3 /usr/lib/liblapack.so.3
      .bashrc加入:export LD_LIBRARY_PATH=/opt/OpenBLAS/lib:$LD_LIBRARY_PATH
  2. 安装faiss
    • git clone https://github.com/facebookresearch/faiss.git
      cd faiss
      cp example_makefiles/makefile.inc.Linux makefile.inc
      ./configure –with-blas=/usr/lib/libblas.so.3
      (测试:make misc/test_blas然后运行./misc/test_blas)
      make
      make install (安装到/usr/local/lib 和 /usr/local/include/faiss)
      make py(安装到./python/faiss,把这个faiss文件夹拷贝到你的python的/lib/python2.7/下面)

三、faiss的几种基本索引

faiss包含了较多索引方式(详见https://github.com/facebookresearch/faiss/wiki/Faiss-indexes),这里介绍一下tutorial/python目录下使用的三种:

  • IndexFlatL2
    • 基于brute-force计算向量的L2距离,就是暴搜。检索速度慢,适用于小数据量。
  • IndexIVF
    • 加快索引的方式之一,与暴搜对比就是需要train,把向量空间下的数据切割为Voronoi细胞,检索只对向量所在细胞和周围细胞进行检索。
  • IndexIVFPQ
    • 基于Product Quantizer对高维向量进行压缩,降低内存占用。

3.1 IndexFlatL2

直接上例子:faiss处理固定维度的向量的集合,维度通常为几十到几百,这些集合可以存储在矩阵中,行主存储。

import numpy as np
d = 64 # 维度
nb = 100000 # 数据库大小
nq = 10000 # 要搜索的query
np.random.seed(1234) # 确定种子,使随机数可重现
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000. # 每一行的第一个列增加一个等差数列的对应项数
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.
print(xq.shape) # (10000, 64)
print(xb.shape) # (100000, 64)
import faiss # make faiss available
index = faiss.IndexFlatL2(d) # 构建FlatL2索引
print(index.is_trained)
print(index.ntotal)
index.add(xb) # 向索引中添加向量。add操作如果没有提供id,则使用向量序号作为id。
print(index.ntotal)
k = 4 # 搜索多少个临近向量
D, I = index.search(xb[:5], k) # 用xb的前五行本身自己搜索自己,完整性检查,用于测试
print("I=")
print(I)
#I=
#[[  0 393 363  78 924]
# [  1 555 277 364 617]
# [  2 304 101  13 801]
# [  3 173  18 182 484]
# [  4 288 370 531 178]]
# I输出类似于上面,每行对应着相应向量的搜索结果。k为多少就有多少列,distance低的排在前面。
# 可以看到前五行的第一列确实是0~4
print("D=")
print(D)
#[[0.        7.1751733 7.207629  7.2511625]
# [0.        6.3235645 6.684581  6.7999454]
# [0.        5.7964087 6.391736  7.2815123]
# [0.        7.2779055 7.5279865 7.6628466]
# [0.        6.7638035 7.2951202 7.3688145]]
# 可以看到第一行第一列都是0,意思是向量与自己本身的距离为0
D, I = index.search(xq, k) # 搜索
print(I[:5]) # 最初五个向量查询的结果
print(I[-5:]) # 最后五个向量查询的结果

当建立和训练完索引时,可以对索引执行两个操作:addsearch

将元素添加到索引。我们还可以输出索引的两个状态变量:
is_trained 表示索引是否需要训练的布尔值,
ntotal 索引中向量的数量。

IndexFlat搜索的结果是精确的,可以作为评估其他几个索引的测试准确性的标准。

3.2 IndexIVFFlat

对于暴搜来说,海量数据搜索速度太慢,那么需要预训练把向量都聚类。这里使用IndexIVFFlat来加快搜索速度。IndexIVFFlat是faiss的倒排索引,把数据构成的向量空间切割为Voronoi细胞,每个向量落入其中一个Voronoi细胞中。在搜索时,只有查询x所在细胞中包含的数据库向量y与少数几个相邻查询向量进行比较。

训练的时候还需要有一个量化器,用于决定以什么方式将向量分配给Voronoi细胞。每个细胞由一个质心定义,找到一个向量所在的Voronoi细胞包括在质心集中找到该向量的最近邻居。

搜索方法有两个参数:
nlist 划分Voronoi细胞的数量
nprobe 执行搜索访问的单元格数(不包括nlist),该参数调整结果速度和准确度之间折中的一种方式。如果设置nprobe=nlist则结果与暴搜一致。

上代码:

import numpy as np
d = 64                           # dimension
nb = 100000                      # database size
nq = 10000                       # nb of queries
np.random.seed(1234)             # make reproducible
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.

import faiss
nlist = 100
k = 4
quantizer = faiss.IndexFlatL2(d)  # 内部的索引方式
index = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)
# here we specify METRIC_L2, by default it performs inner-product search
print("before train")
assert not index.is_trained
index.train(xb)
assert index.is_trained
print("before add")
index.add(xb)                  # add may be a bit slower as well
D, I = index.search(xq, k)     # actual search
print(I[-5:])                  # neighbors of the 5 last queries
index.nprobe = 10              # default nprobe is 1, try a few more
D, I = index.search(xq, k)
print(I[-5:])                  # neighbors of the 5 last queries

 

3.3 IndexIVFPQ

上面两种索引都是存储的完整向量,下面介绍一种压缩向量的方法。IndexIVFPQ基于PQ算法压缩向量。在这种情况下,由于向量没有精确存储,搜索方法返回的距离也是近似值

import numpy as np

d = 64 # dimension
nb = 100000 # database size
nq = 10000 # nb of queries
np.random.seed(1234) # make reproducible
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.
xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.

import faiss

nlist = 100
m = 8
k = 4
quantizer = faiss.IndexFlatL2(d) # 内部的索引方式
index = faiss.IndexIVFPQ(quantizer, d, nlist, m, 8)
# 每个向量都被编码为8个字节大小
index.train(xb)
index.add(xb)
D, I = index.search(xb[:5], k) # sanity check
print(I)
print(D)
#[[   0   78  714  372]
# [   1 1063  555  277]
# [   2  304  134   46]
# [   3  773   64    8]
# [   4  288  531  827]]
#[[1.6675376 6.1988335 6.4136653 6.4228306]
# [1.4083313 6.023788  6.025648  6.284443 ]
# [1.6988016 5.592166  6.139589  6.6717234]
# [1.7987373 6.625978  6.7166452 6.865783 ]
# [1.5371588 5.7953157 6.38059   6.4141784]]
# 可以看到确实搜索到了正确的结果,但是第一行第一列的distance不为零,属于有损压缩。
# 虽然与接下来的几列(其他几个搜索结果)对比还是有几倍的优势。
index.nprobe = 10 # 与以前的方法相比
D, I = index.search(xq, k) # search
print(I[-5:])

另外搜索真实查询时,虽然结果大多是错误的(与刚才的IVFFlat进行比较),但是它们在正确的空间区域,而对于真实数据,情况更好,因为:

  • 统一数据很难进行索引,因为没有规律性可以被利用来聚集或降低维度
  •  对于自然数据,语义最近邻居往往比不相关的结果更接近。

简化指标结构:
由于构建索引可能会变得复杂,因此有一个工厂函数用于接受一个字符串来构造响应的索引。上面的索引可以通过以下简写获得:

index = faiss.index_factory(d,“ IVF100,PQ8 ”)

更换PQ4用Flat得到的IndexFlat。当预处理(PCA)应用于输入向量时,工厂特别有用。例如,预处理的工厂字符串通过PCA投影将矢量减少到32维为:“PCA32,IVF100,Flat”。

四、index总结

选择:

no build time, high query time, high storage, exact accuracy Faiss IndexFlat
low build time, med query time, high storage, high accuracy Faiss IndexIVFFlat
med build time, low query time, low-med storage, med-high accuracy Faiss IndexIVFPQ
very high build time, low query time, low-high storage (whether stored as a k-NN graph or raw data), high accuracy N-Descent by Dong et al. (e.g., nmslib)

 

 

faiss索引调研(一)——基础知识

零、Delaunay 三角网

【定义】三角剖分:假设V是二维实数域上的有限点集,边e是由点集中的点作为端点构成的封闭线段, E为e的集合。那么该点集V的一个三角剖分T=(V,E)是一个平面图G,该平面图满足条件:
1.除了端点,平面图中的边不包含点集中的任何点。
2.没有相交边。
3.平面图中所有的面都是三角面,且所有三角面的合集是散点集V的凸包。
在实际中运用的最多的三角剖分是Delaunay三角剖分,它是一种特殊的三角剖分。先从Delaunay边说起:
【定义】Delaunay边:假设E中的一条边e(两个端点为a,b),e若满足下列条件,则称之为Delaunay边:存在一个圆经过a,b两点,圆内(注意是圆内,圆上最多三点共圆)不含点集V中任何其他的点,这一特性又称空圆特性。
【定义】Delaunay三角剖分:如果点集V的一个三角剖分T只包含Delaunay边,那么该三角剖分称为Delaunay三角剖分。
【定义】假设T为V的任一三角剖分,则T是V的一个Delaunay三角剖分,当前仅当T中的每个三角形的外接圆的内部不包含V中任何的点。

一、Voronoi cell

http://www.csie.ntnu.edu.tw/~u91029/Neighbor.html

https://www.ryanligod.com/2018/10/09/2018-10-09%20%E7%BB%B4%E8%AF%BA%E5%9B%BE%EF%BC%88Voronoi%20Diagram%EF%BC%89%E5%88%86%E6%9E%90%E4%B8%8E%E5%AE%9E%E7%8E%B0/

一个平面上散步着一些点,平面上的每一处都各自归属于其最近的点,属于不同点的面的交界处就形成了分界线,是左右两个不同类点的中垂线。简单来说就是,临近的点的中垂线形成了Voronoi图。

生成Voronoi的方法之一Delaunay 三角剖分算法:生成 Voronoi 图时先生成其对偶元 Delaunay 三角网,再找出三角网每一三角形的外接圆圆心,最后连接相邻三角形的外接圆圆心,形成以每一三角形顶点为生成元的多边形网。如下图:

 

二、PQ

https://blog.csdn.net/guanyonglai/article/details/78468673

https://blog.csdn.net/CHIERYU/article/details/50321473

Product Quantizer乘积量化,用于减小向量存储所需内存的一种方法。简单来说就是把每个索引向量切割成m个子向量,每个子向量自己用k-means聚类形成m个码本。对于检索库中的向量,把每个向量用这m个子向量的索引号来表示。

举个例子,比如说库里面有100万个128维向量,把这128维向量分为8个子向量,那么每个子向量就是128/8=16维子向量。之后在每个子向量形成的子向量空间中用k-meas聚类为256个类。然后把每个原始128维的向量的每个子向量在其对应的子向量空间中查找到自己属于哪个类,8个子向量分别在8个堆中查找属于256个类中的哪一个类,这样这个向量库就可以用256的八次方大小的矩阵来表示。然后在查找的时候,首先查看当前向量的1/8短向量,搜索到最近邻之后就可以排除掉向量库里面的其他255/256个向量,依此类推。

算法主要通过以下几个步骤:

  1. 空间切分:将D维空间切分为M份(在上面的例子上M=8);
  2. 量化:计算每个短向量距离最近的聚类中心;
  3. 压缩:把原始向量生成为M维压缩向量;
  4. 距离计算:如何计算两个压缩向量的距离:
    1. 左为对称计算:直接使用两个压缩向量x,y的索引值所对应的码字q(x),q(y)之间的距离代替。这个距离可以离线计算。
    2. 右为非对称计算:使用x,q(y)之间的距离代替x,y之间的距离,其中x是测试向量。虽然y的个数可能有上百万个,但是q(y)的个数只有k个,对于每个x,我们只需要在输入x之后先计算一遍x和k个q(y)的距离

总结:PQ其实可以类比于欧式空间中的笛卡尔积(假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。)。

三、几种距离

编辑距离:给定 2 个字符串 a, b. 编辑距离是将 a 转换为 b 的最少操作次数,操作只允许如下 3 种:
  1. 插入一个字符,例如:fj -> fxj
  2. 删除一个字符,例如:fxj -> fj
  3. 替换一个字符,例如:fxj -> fyj

Jaccard距离:

 

四、LSH

局部敏感哈希的基本思想类似于一种空间域转换思想,LSH算法基于一个假设,如果两个文本在原有的数据空间是相似的,那么分别经过哈希函数转换以后的它们也具有很高的相似度;相反,如果它们本身是不相似的,那么经过转换后它们应仍不具有相似性。

五、HNSW(Hierarchical Navigable Small World)

https://www.ryanligod.com/2018/11/27/2018-11-27%20HNSW%20%E4%BB%8B%E7%BB%8D/

  1. 对数据库向量进行Delaunay 三角剖分
  2. 搜索时:
    1. 该算法贪婪地遍历来自上层的元素,直到达到局部最小值。贪婪算法:
      1. 算法计算从查询 qq 到当前顶点的朋友列表的每个顶点的距离,然后选择具有最小距离的顶点。
      2. 如果查询与所选顶点之间的距离小于查询与当前元素之间的距离,则算法移动到所选顶点,并且它变为新的当前顶点。
      3. 算法在达到局部最小值时停止:一个顶点,其朋友列表不包含比顶点本身更接近查询的顶点
    2. 之后,搜索切换到较低层(具有较短 link),从元素重新开始,该元素是前一层中的局部最小值,并且该过程重复。
    3. 通过采用层状结构,将边按特征半径进行分层,从而将 NSW 的计算复杂度由多重对数(Polylogarithmic)复杂度降到了对数(logarithmic)复杂度。

六、kd树

https://zhuanlan.zhihu.com/p/23966698

 

Kubernetes1.13.2 使用GPU

  1. 首先安装nvidia驱动,nvidia-smi有输出即安装成功
  2. 安装docker,版本最新就行,当前装的是1.13.1
  3. 安装nvidia-docker,https://github.com/NVIDIA/nvidia-docker
    1. Centos7使用的是nvidia-container-runtime-hook
    2. hook和nvidia-docker的区别:https://xigang.github.io/2018/11/08/nvidia-container-runtime/,简单来讲就是nvidia-docker1实现了docker client的封装,并且在容器启动的时候将GPU device和libraries挂载到容器中,而第二代主要是通过修改json替换原来的runc为NVIDIA Container runtime,然后在NVIDIA Container runtime中,在原有的runc上加一个hook,用于调用libnvidia-container库,该库提供一个库和一个简单的CLI工具,用于使得容器可以调用NVIDIA GPU。
  4. 安装kubernetes,当前安装的是1.13.2
    1. docker pull jicki/kube-proxy:v1.13.2
      docker pull jicki/kube-controller-manager:v1.13.2
      docker pull jicki/kube-scheduler:v1.13.2
      docker pull jicki/kube-apiserver:v1.13.2
      docker pull jicki/coredns:1.2.6
      docker pull jicki/cluster-proportional-autoscaler-amd64:1.3.0
      docker pull jicki/kubernetes-dashboard-amd64:v1.10.0
      docker pull jicki/etcd:3.2.24
      docker pull jicki/node:v3.1.3
      docker pull jicki/ctl:v3.1.3
      docker pull jicki/kube-controllers:v3.1.3
      docker pull jicki/cni:v3.1.3
      docker pull jicki/pause:3.1
      docker pull jicki/pause-amd64:3.1
      docker pull quay.io/coreos/flannel:v0.10.0-arm
      docker pull quay.io/coreos/flannel:v0.10.0-ppc64le
      docker pull quay.io/coreos/flannel:v0.10.0-s390x
    2. docker tag jicki/kube-proxy:v1.13.2 k8s.gcr.io/kube-proxy:v1.13.2
      docker tag jicki/kube-controller-manager:v1.13.2 k8s.gcr.io/kube-controller-manager:v1.13.2
      docker tag jicki/kube-scheduler:v1.13.2 k8s.gcr.io/kube-scheduler:v1.13.2
      docker tag jicki/kube-apiserver:v1.13.2 k8s.gcr.io/kube-apiserver:v1.13.2
      docker tag jicki/coredns:1.2.6 k8s.gcr.io/coredns:1.2.6
      docker tag jicki/cluster-proportional-autoscaler-amd64:1.3.0 k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.3.0
      docker tag jicki/kubernetes-dashboard-amd64:v1.10.0 k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.0
      docker tag jicki/etcd:3.2.24 k8s.gcr.io/etcd:3.2.24
      docker tag jicki/node:v3.1.3 k8s.gcr.io/node:v3.1.3
      docker tag jicki/ctl:v3.1.3 k8s.gcr.io/ctl:v3.1.3
      docker tag jicki/kube-controllers:v3.1.3 k8s.gcr.io/kube-controllers:v3.1.3
      docker tag jicki/cni:v3.1.3 k8s.gcr.io/cni:v3.1.3
      docker tag jicki/pause:3.1 k8s.gcr.io/pause:3.1
      docker tag jicki/pause-amd64:3.1 k8s.gcr.io/pause-amd64:3.1
    3. docker rmi jicki/kube-proxy:v1.13.2
      docker rmi jicki/kube-controller-manager:v1.13.2
      docker rmi jicki/kube-scheduler:v1.13.2
      docker rmi jicki/kube-apiserver:v1.13.2
      docker rmi jicki/coredns:1.2.6
      docker rmi jicki/cluster-proportional-autoscaler-amd64:1.3.0
      docker rmi jicki/kubernetes-dashboard-amd64:v1.10.0
      docker rmi jicki/etcd:3.2.24
      docker rmi jicki/node:v3.1.3
      docker rmi jicki/ctl:v3.1.3
      docker rmi jicki/kube-controllers:v3.1.3
      docker rmi jicki/cni:v3.1.3
      docker rmi jicki/pause:3.1
      docker rmi jicki/pause-amd64:3.1
  5. 搭建集群
    1. 开启kubectl服务:systemctl enable kubelet.service
    2. kubeadm init –kubernetes-version=v1.13.2 –pod-network-cidr=10.244.0.0/16 –apiserver-advertise-address=<your_ip>
    3. apply flannel:
      1. mkdir -p ~/k8s/
        cd ~/k8s
        wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
        kubectl apply -f kube-flannel.yml
      2. 有可能识别不到网卡,需要手动添加iface=eth0
      3. master加入调度:kubectl taint nodes node1 node-role.kubernetes.io/master-
  6. 安装NVIDIA device plugin,插件以daemonset部署,通过label筛选出有GPU的集群:
    1. kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.12/nvidia-device-plugin.yml
  7. 测试:
    1. apiVersion: v1
      kind: Pod
      metadata:
        name: test-gpu
      spec:
        volumes:
          - hostPath:
              path: /usr/lib64/nvidia
            name: lib
        containers:
        - env:
          - name: TEST
            value: "GPU"
          imagePullPolicy: Always
          name: gpu-container-1
          image: tensorflow/tensorflow:latest-gpu
          resources:
            limits:
              nvidia.com/gpu: 1
          volumeMounts:
              - mountPath: /usr/local/nvidia/lib64
                name: lib
  8. 注意:
    1. 教程中说要设置docker json加上default runtime的,都不需要,最新版本的docker已经有了。
    2. 很多教程中都说要设置kubectl的参数Accelerators=true。其实不需要,因为1.13.2已经莫任务true了。设置了之后启动的时候报错unrecognized feature gate: Accelerators。因为这个标签已经在1.11之后已经废弃了。
  9. 问题:
    1. 跑任务的时候报错CUDA_ERROR_NO_DEVICE,网上查了之后有两种原因:一种是CUDA_VISIBLE_DEVICES设置的问题,一种是cuda驱动没装好。后面发现是因为程序内设置了CUDA_VISIBLE_DEVICES=1,CUDA_VISIBLE_DEVICES的意思是是编号为几的GPU对程序可见。k8s调度的时候会随机选择/dev/下面的任意一张设备挂载在镜像内,如果挂载的不是CUDA_VISIBLE_DEVICES指定的那个就会失败。通过修改CUDA_VISIBLE_DEVICES为0,1,2,3就可以运行了:
    2. 跑job的时候希望能够使用job的自动清理功能:spec.ttlSecondsAfterFinished,但是跑的时候发现并没有生效,kubectl get job xxx -o json的时候也发现没有设置上去。后面发现是需要开启TTLAfterFinished这个feature-gates:
      1. kubectl需要加feature-gate:
          vim /etc/sysconfig/kubelet
          KUBELET_EXTRA_ARGS=–feature-gates=TTLAfterFinished=true
          systemctl daemon-reload
          systemctl restart kubelet.service
      2. apiserver、controller-manager、scheduler都需要加–feature-gates=TTLAfterFinished=true:(kubeadm 将会为 API server、controller manager 和 scheduler 生成 Kubernetes 的静态 Pod manifest 文件,并将这些文件放入 /etc/kubernetes/manifests 中)
          cd /etc/kubernetes/manifests
          编辑kube-apiserver.yaml、kube-controller-manager.yaml、kube-scheduler.yaml添加flag
          重启:kubectl get po -nkube-system delete掉相应的pod
  10.  参考:
    1. https://bluesmilery.github.io/blogs/afcb1072/
    2. https://www.kubernetes.org.cn/4956.html
    3. http://likakuli.com/post/2018/09/06/kubernetes_gpu/
    4. https://k8smeetup.github.io/docs/admin/kubeadm/

python访问hdfs的几种方式

零、搭建

快速搭建单节点的方法:https://blog.csdn.net/yu616568/article/details/42780383

一、python库

hdfs库

pip install hdfs

只可以使用hdfs的http端口(通常是50070),不支持rpc端口(9000或8020)

需要在启动hdfs节点的时候配置:

使用也很方便:

from hdfs import *
fs = InsecureClient(hdfs_url, root=hdfs_root, user=hdfs_proxy,timeout=hdfs_timeout)
fs_folders_list = fs.list(hdfs_root)

2.2.2的文档:https://media.readthedocs.org/pdf/hdfscli/latest/hdfscli.pdf

 

snakebite库

O’Reilly的书Hadoop with Python推荐的库,可以用rpc端口,但是只可以下载,(截止到20181225)没有上传的接口

使用:返回的是一个generator

from snakebite.client import Client
client = Client("localhost", 8020, use_trash=False)
for x in client.ls(['/']):
    print x

snakebite的github:https://github.com/spotify/snakebite

pyhdfs库

pyhdfs是对libhdfs的python封装库,

装起来很麻烦,pip install python-hdfs但是还是不能访问,是需要有libhds,看了网上要装的东西挺多的,

https://pypi.org/project/PyHDFS/

各种安装方法:https://blog.csdn.net/w894607785/article/details/50205857

libhdfs库

libhdfs 是HDFS的底层C函数库, 由hadoop官方提供。

安装:pip install hdfs3,还需要安装libhdfs,如果是Centos必须使用源码编译安装,没折腾出来。

使用:from hdfs3 import HDFileSystem
hdfs = HDFileSystem(host='localhost', port=8020)

文档:https://hdfs3.readthedocs.io/en/latest/install.html

pyarrow库

安装pyhdfs的时候发现的一个库,可以用rpc端口。

调用java来访问hdfs的库,需要装jre、hadoop客户端:

export JAVA_HOME=/home/work/java/jdk1.8.0_60
export PATH=$JAVA_HOME/jre/bin:$PATH
export HADOOP_HOME=/home/work/hadoop-2.6.0-cdh5.13.1
export HADOOP_LIBEXEC_DIR=${HADOOP_HOME}/libexec
export HADOOP_USER_NAME=<your_user_name>

因为Clouder CDH3B3开始后hadoop.job.ugi不再生效,所以装客户端的时候需要配置环境变量HADOOP_USER_NAME来修改访问用户名

使用:

import pyarrow as pa
fs = pa.hdfs.connect(hdfs_url, int(hdfs_port), user=hdfs_user, kerb_ticket=None)
fs.ls(hdfs_root)

带了Kerberous的话得看一下:https://zhuanlan.zhihu.com/p/43887793

使用参考文档:
访问:https://arrow.apache.org/docs/python/filesystems.html#hadoop-file-system-hdfs
接口:https://arrow.apache.org/docs/python/generated/pyarrow.HdfsFile.html
https://blog.csdn.net/zyb378747350/article/details/79020787

 

二、调用shell

用os.system(cmd)调用

参考:http://wesmckinney.com/blog/python-hdfs-interfaces/这篇文章说的比较全面

三、其他

安装hadoop客户端的时候一定要下一个与服务端版本匹配的,修改etc/hadoop/core-site.xml的fs.default.name为服务端即可。