MapReduce初探

本文主要针对论文“MapReduce: Simplified Data Processing on Large Clusters”进行了概括及总结。

目的

  • 作业输入数据的规模较大
  • 这些任务的运行时间受限,因而需要利用数据中心内的海量节点进行分布式计算
  • 容错及异常处理较复杂且维护成本较高

解决方案

提出了MapReduce架构,将任务的计算流程分为Map和Reduce两个阶段,方法均由用户提供。

  • MAP
    • 输入:input pair, e.g. (1, “hello world”) in Word Count
    • 输出:a set of intermediate key/value pair, e.g. [(“hello”, [“1”, “2”]), (“world”, [“1”])] in Word Count
  • REDUCE
    • 输入:an intermediate key + a set of values for this key,如MAP过程的输出
    • 输出:合并上述values,通常最后为zero or one value
  • 案例
    • Distributed Grep, Count of URL Access Frequency

执行流程

  1. 将输入数据切分为M块,单块大小为16-64MB;
    • 128MB,适用于大文件
    • 用户按需求自定义
  2. 选取M+R个状态为idle的worker分配任务;
    • map任务尽量在split块对应节点或其“附近”执行(same network swith)
    • Master节点维护任务状态信息(idle, in-progress, completed),HTTP通信
    • 若W为用户期望使用的worker数量,一般来说,M通常远大于W,R通常为W的几倍
      • M和R由用户指定,用户根据需求估计,R的数量跟业务相关
      • W为用户申请的并发资源量
  3. Map Worker读取输入split,对每个pair执行MAP程序;
    • Map读split文件的方式
      • 没有对文件实际的切割,只是记录了要处理的数据的位置和长度
      • map数量与split 数量,splitSize=max(minSize, Math.min(goalSize, blockSize))
        • minSize,用户指定的最小切分
        • blockSize,HDFS块大小(128MB)
        • goalSize=totalSize/numSplits,numSplits,用户期望的map数量
          • 若splitSize大于blockSize,说明需要将多个block合成到一个split,这样有部分block数据需要通过网络读取
          • 若splitSize小于blockSize,说明需要将一个block拆成多个split,增加Map任务数
          • 假设splitSize是默认的64M,现在输入包含3个文件,这3个文件的大小分别为10M,64M,100M,那么这3个文件会被分割为10MB,64MB,64MB,36MB
          • 通常splitSize 就等于blockSize的默认值
        • 一条数据跨split(block),只要不是第一个split,忽略第一条数据
      • 合并小文件,避免block对内存的浪费
    • 提供了默认的读取类型,如”text”, “key-value pair”,各类型能够确定数据切分的正确性
    • 用户自定义reader接口,从数据库,内存中读取数据
    • 图中表示实际读取的情况
  4. Map任务将中间结果缓存至内存中,并定期溢写到磁盘(80%);
    • 划分函数(partitioning function)将中间结果分割为R片区域(region)
      • 划分函数利用hash,例如{hash(key) mod R},{hash(Hostname(urlkey)) mod R}
      • 划分数量与Reduce任务数量相同
      • Region内部的中间结果默认按key增序排列,方便用于随机访问,排序,有时可能说外排序
      • 合并函数(Combiner)在map阶段部分合并key相同的value,本质与Reduce相同,减少网络带宽消耗
    • 缓存结果在磁盘中的位置会被传递至Master节点,后续用于Reduce过程
    • 用户生成的临时辅助文件需要用户自定义保证正确性(原子性,幂等性)
      • map重算,用户处理还是框架处理
  5. Reduce worker从Master处获取文件位置信息,RPC读取map worker中的中间结果
    • 所有结果读取后按key进行排序,key值相同的数据被合并
    • 若排序过程中数据量过大需采用外部排序;
  6. Reduce woker逐个处理每个中间结果,对于每个key值及其对应的value set,调用reduce程序
    • Reduce的启动时机,70%
    • Reduce Task启动过早,长时间占用slot,资源利用率低
    • Reduce Task启动过晚,Map-Reduce串行执行,拖延任务运行时间
    • 通过已经运行完成的Map Task运行时间估算正在运行的Map Task的剩余运行时间,当Map阶段剩余时间达到一定值后,才开始调度Reduce Task
  7. 所有map及reduce任务完成后,master唤醒并返回用户程序,生成R个输出文件

上述Map及Reduce的流程可以概括为:

  • Map任务:从GFS读取数据-执行MAP程序-combine过程-输出中间结果至本地磁盘
  • Reduce任务:从map节点读取中间结果-根据key进行排序-执行REDUCE程序-输出结果至GFS

容错控制

  1. Master节点故障
    • 定期checkpoint
      • 代价较高
    • 只有单节点在线,Master故障后Client会一直重连
  2. Worker节点故障
    • Master定期ping每个worker,若无响应,则标记为故障节点
    • 故障节点中的map任务需重做状态为运行中(in-progress)及已完成(completed)的,因为中间结果无法读取
      • 重做map任务后,所有reduce任务均被通知,数据未读取完成的任务要重新读取
      • 大部分情况下,不要影响Reduce,Reduce重做代价较高
    • 故障节点中的reduce任务只需重做状态为运行中(in-progress)的,已完成的结果已被存值GFS
  3. Straggler
    • 当一个MapReduce作业即将完成时,master为剩余状态为in-progress的任务创建多个相同备用任务,任务对应的副本中其中有一个完成即可
    • 预测执行
      • Map和Reduce均有,比例控制
      • Map和Reduce的输出一致性保存
  4. 异常数据记录
    • 程序中的bug可能会导致在读取某部分数据时产生异常,阻止作业继续运行
    • bug不易修复;由第三放库引起;统计分析可忽略
    • 提供直接跳过这部分数据(record)的功能
      • 每个worker配有一个信号处理程序(signal handler),捕捉segmentation violations & bus errors,暂存与MapReduce上下文中
      • 若由用户代码生成,signal handler会向master发送特定UDP信息,若master收到多次提醒,则在该任务重新执行时提示其跳过
      • 数据的record与split之间的关系:record指某一条具体数据,具体引起程序崩溃的record位置会被记录,skip bad record

关于Linux服务器安全防护的基本方法

楔子

服务器的安全防护一直以来都是老生长谈的话题,虽然我们平时接触的服务器影响力一般,不会被攻击者处心积虑利用各种漏洞攻击,但做一些基本的防护措施还是很有必要的,可以避免那些常年活跃在互联网上的自动化攻击。

曾有国外安全研究者做过实验,他们搭建了一台蜜罐服务器,该服务上安装了修改后的SSHD版本,记录所有的登陆尝试和存储的所有会话,一旦被黑客攻击,可以查看到所有暴力破解尝试记录,实验结果也非常有趣。

SSH暴力破解大约自linux系列产品诞生之后,就衍生出来的一种攻击行为,不仅仅SSH暴力破解,ftp、telnet、smtp、mysql等等都是暴力美学黑客的最爱。

本文总结了一些Linux服务器的基本防护方法,可以有效应对大部分普通网络攻击。实验操作系统版本为CentOS 6

修改ssh默认端口22

众所周知,ssh的默认端口为22,这成为了攻击者的首要目标,同时也会引入大量的错误日志。TCP/IP协议中的端口,端口号的范围从0到65535,我们可以指定一个作为ssh登陆端口,注意不要与其它服务冲突。

ssh服务配置文件为/etc/ssh/sshd_config,可以看到端口号指定的配置被注释了,默认为22

#Port 22

在配置文件中增加一行Port 12345后,重启ssh服务service sshd restart,此时,ssh端口改为了12345,登陆时需要额外指定ssh -p 12345 mytestuser@mytestserver

使用Fail2Ban

fail2ban是一个通过监控日志,防止系统密码被暴力破解的工具,它支持大部分常用服务,如sshd, apache, qmail, proftpd, sasl, asterisk等等,当发现服务器有被暴力破解的迹象时,fail2ban会采取多种手段进行应对,如iptables, tcp-wrapper, shorewall, mail notifications等等。

安装依赖

必选
  • Python >= 2.4
可选
  • iptables
  • shorewall
  • tcp-wrappers
  • a working mail command
  • Gamin the File Alteration Monitor

安装步骤

  1. 官网下载地址

    http://www.fail2ban.org/wiki/index.php/Downloads

  2. 解压及安装

     [root@jsi-dell13 downloads]# tar xzvf 0.8.14.tar.gz
     [root@jsi-dell13 downloads]# cd fail2ban-0.8.14/
     [root@jsi-dell13 fail2ban-0.8.14]# ./setup.py install
     [root@jsi-dell13 fail2ban-0.8.14]# cp files/redhat-initd /etc/init.d/fail2ban
     [root@jsi-dell13 fail2ban-0.8.14]# chmod 755 /etc/init.d/fail2ban 
    
  3. 配置开机启动

     [root@jsi-dell13 fail2ban-0.8.14]# ln -s /etc/init.d/fail2ban /etc/rc2.d/S20fail2ban
    
  4. 配置日志轮询

    创建文件/etc/logrotate.d/fail2ban,写入

    /var/log/fail2ban.log {

    weekly

    rotate 7

    missingok

    compress

    postrotate

    /usr/bin/fail2ban-client set logtarget /var/log/fail2ban.log >/dev/null

    endscript

    }

  5. 防止ssh字典攻击

    修改配置文件/etc/fail2ban/jail.conf如下

    [ssh-iptables]

    #enabled = false

    enabled = true

    filter = sshd

    action = iptables[name=SSH, port=ssh, protocol=tcp]

        sendmail-whois[name=SSH, dest=you@example.com,

        sender=fail2ban@example.com, sendername=“Fail2Ban”]

    #logpath = /var/log/sshd.log

    logpath = /var/log/secure

    maxretry = 5

    以上配置的含义为对于在(findtime)600s内输错5次密码的ip,使用iptables将该ip屏蔽(bandtime)600s。其中findtime和bandtime均可以通过配置修改。详情参见fail2ban官方手册

禁止root用户通过ssh方式登陆

root用户几乎是所有类UNIX系统中都存在的用户,攻击者也常常使用root用户暴力攻击,如果不禁止root远程ssh登陆,攻击者获取密码只是时间问题。

编辑文件/etc/ssh/sshd_config,修改配置选项为PermitRootLogin no,重启ssh服务service sshd restart

提示:请确保服务器上还有其它可ssh登录的用户,创建用户步骤如下:

[root@JSI-iDPL02 ~]# useradd jsitest
[root@JSI-iDPL02 ~]# passwd jsitest

使用公钥密钥的认证方式

RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

1973年,在英国政府通讯总部工作的数学家克利福德·柯克斯(Clifford Cocks)在一个内部文件中提出了一个相同的算法,但他的发现被列入机密,一直到1997年才被发表。

对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。假如有人找到一种快速因数分解的算法的话,那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到2013年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。

具体步骤为:

  1. 生成公钥密钥

     [root@JSI-iDPL02 ~]# ssh-keygen -C "jsitest@JSI-iDPL02" -t rsa -b 2048 -f jsitest-JSI-iDPL02
     Generating public/private rsa key pair.
     Enter passphrase (empty for no passphrase): 
    
     Enter same passphrase again: 
    
     Your identification has been saved in jsitest-JSI-iDPL02.
    
     Your public key has been saved in jsitest-JSI-iDPL02.pub.
     The key fingerprint is:
     96:bb:d0:67:11:c8:dc:be:bd:6d:00:7c:59:63:e3:3a jsitest@JSI-iDPL02
     The key's randomart image is:
     +--[ RSA 2048]----+
     |                 |
     |       o o    =  |
     |        +.o  = o |
     |         oo.o .  |
     |        S oo .   |
     |       o . +E    |
     |      . o + .o   |
     |       . +   o.  |
     |        .   ...  |
     +-----------------+
    

    Enter passphrase的输入为加密所用的字符串,可以视安全强度决定是否置空。

    各参数含义为:

    • -C 是对密钥的一个说明,有助于区分不同的密钥用途。

    • -t 和 -b 分别指定要生成的密钥类型和密钥长度。

    • -f 指定生成的密钥对文件名。公钥文件名为jsitest-JSI-iDPL02.pub,私钥为jsitest-JSI-iDPL02。

    更多参数请参考ssh-keygen手册

  2. 当前目录下分别生成了公钥jsitest-JSI-iDPL02.pub以及密钥jsitest-JSI-iDPL02,将密钥拷贝至客户端备用,将公钥拷贝至服务器端备用

  3. 服务器端导入公钥,将对应的公钥加入到服务器上需要登录的用户的home目录下的.ssh/authorized_keys文件中

     [root@JSI-iDPL02 ~]# cd /home/jsitest/
     [root@JSI-iDPL02 jsitest]# mkdir .ssh
     [root@JSI-iDPL02 ~]# cat jsitest-JSI-iDPL02.pub >> /home/jsitest/.ssh/authorized_keys
    

    事实上authorized_keys文件的准确名字是由 sshd_config 中的 AuthorizedKeysFile 配置指定给定的。man sshd_config 获取详细的说明信息。

    注意:authorized_keys文件及其所在的目录以及父目录(一直上溯到该用户的HOME目录为止)的权限必须设置为不能被组和其他人写(可以通过chmod og-w确认),否则其他人只需要修改这个文件即可以以该身份登录到系统上。

  4. OpenSSH服务端配置

    OpenSSH服务器端配置文件一般为/etc/ssh/sshd_config,和公钥认证有关的两个配置项是:

     #RSAAuthentication yes
     #PubkeyAuthentication yes
    

    其缺省值一般为 yes。如果希望仅打开公钥认证,禁用其他的认证方式,则可以修改下列配置项:

     PasswordAuthentication no
     ChallengeResponseAuthentication no  
     UsePAM no
    

    重启ssh服务使修改生效

     service sshd restart
    
  5. 用户登录

    对 OpenSSH 客户端,可以通过ssh -i jsitest-JSI-iDPL02 jsitest@JSI-iDPL快速测试是否工作。

    更一般的方法是将私钥文件jsitest-JSI-iDPL02拷贝至客户端.ssh/目录下,设置.ssh/config配置对不同主机和用户进行配置。如下例:

     Host idpl3                                  #别名
         HostName 10.4.9.191                     #完整的域名
         User jsitest                            #登录该域名使用的账号名
         IdentityFile ~/.ssh/jsitest-JSI-iDPL03 #私钥文件的路径
    

    这样就可以简化登陆服务器的过程了:

     [root@JSI-iDPL03 ~]# ssh idpl2
     Enter passphrase for key '/root/.ssh/jsitest-JSI-iDPL02': 
     Last login: Wed Sep 17 14:38:05 2014 from jsi-idpl03
     [jsitest@JSI-iDPL02 ~]$
    

禁用ping

很久以前,一部分操作系统(例如win95),不能很好处理过大的Ping包,在当时,大部分电脑无法处理大于IPv4最大封包大小(65,535字节)的ping封包。因此发送这样大小的ping可以令目标电脑崩溃。导致出现了Ping to Death的攻击方式(用大Ping包搞垮对方或者塞满网络),随着操作系统的升级,网络带宽的升级、计算机硬件的升级,大Ping包基本上没有很大的攻击效果(分布式攻击除外),如果一定要使用Ping包去攻击别的主机,除非是利用TCP/IP协议的其他特性或者网络拓扑结构的缺陷放大攻击的力度(所谓正反馈),就是俗称的洪水ping攻击。

不过,大部分机构,特别是一些超算中心还是会选择将服务器的ping功能禁掉,以避免不必要的麻烦。

禁用的方法有两种:

  • 修改文件/proc/sys/net/ipv4/icmp_echo_ignore_all

    不过这种方法只对ipv4有效,ipv6不提供此功能。

      echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
    
  • 添加iptables规则

    对于ipv4,在/etc/sysconfig/iptables中增加:

    -A INPUT -j REJECT —reject-with icmp-host-prohibited

    重启iptables

      service iptables restart
    

    ipv6的配置文件是/etc/sysconfig/ip6tables,添加规则:

    -A INPUT -j REJECT —reject-with icmp6-adm-prohibited

    重启ip6tables

      service ip6tables restart
    

至此,服务器不会相应任何ping消息。

限制用户的su操作

除了在外部做好防御边界,服务器内部同样需要做好权限管制,当用户需要对服务器进行一些权限较高的维护时,需要通过su切换到root用户,所以为了减少安全隐患,需要限制非管理员的su提权操作。

Linux中有wheel组和staff组的概念,wheel组就类似于管理员的组,只有在这个组中的用户才能进行su操作,否则即使知道root密码,也不能通过su命令切换到root用户。具体步骤为:

  1. 修改/etc/pam.d/su文件,将auth required pam_wheel.so use_uid的注释去掉。
  2. 修改/etc/login.defs文件,增加一行SU_WHEEL_ONLY yes配置
  3. 将新用户jsitest添加到wheel组中

     usermod -G wheel jsitest
    

至此,只有在wheel组中的用户才能通过su切换至root用户

Reference

[1] 四大Linux服务器攻击方式及防范策略[EB/OL]. http://www.enet.com.cn/article/2012/0815/A20120815150578.shtml

[2] SSH Brute Force – The 10 Year Old Attack That Still Persists[EB/OL]. Daniel Cid. http://blog.sucuri.net/2013/07/ssh-brute-force-the-10-year-old-attack-that-still-persists.html

[3] 伪装攻击IP地址的洪水Ping攻击详解[EB/OL]. http://www.edu.cn/sqt_9968/20110318/t20110318_589483.shtml

[4] SSH 公钥认证[EB/OL]. http://blog.knownsec.com/2012/05/ssh-%E5%85%AC%E9%92%A5%E8%AE%A4%E8%AF%81/

[5] fail2ban Main Page[EB/OL]. http://www.fail2ban.org/wiki/index.php/Main_Page

[6] 使用fail2ban防止暴力破解ssh及vsftpd密码[EB/OL]. https://www.centos.bz/2012/04/prevent-ssh-break-in-with-fail2ban/

[7] RSA加密算法[EB/OL]. http://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95

Intel MIC初探(一):MIC架构及编程模型概览

楔子

Intel MIC(Many Integrated Core)架构是将多个核心整合在一起的处理器,面向HPC(High Performance Computing)领域,旨在引领行业进入百亿亿次计算时代,在其计算机体系中,并非欲取代CPU,而是作为协处理器存在的。MIC芯片通常有数十个精简的x86核心,提供高度并行的计算能力。虽然Intel官方声称原生的CPU程序无需进行大的改动即可在MIC芯片上运行,但是笔者在具体的应用移植过程中发现,真实的应用在MIC架构下通常都会在规模、内存以及第三方库移植等各方面受到一定的制约。

本系列文章将结合实际使用场景对Intel MIC架构及相关技术做简要介绍,并针对两个具有代表性的应用,提出一些启发式的应用移植方法。另外,本文所有的引用文献以及相关参考资料均在文后列出,以资参考。

硬件架构

片上对称多处理器(Symmetric Multiprocessor on-a-chip,SMP)是对Intel MIC架构的准确描述方式,Intel Xeon Phi协处理器是基于Intel MIC架构的首款产品。协处理器卡的核心是Intel Xeon Phi协处理器芯片,由61个IA(Intel Architecuture)核组成,这些核执行IA指令集,每个核有4个完全相同的硬件线程。

关于MIC的缓存组织,每个核的二级缓存组织包括一级数据缓存和指令缓存,大小均为32KB,另外每个核还设计有一个私有的(本地)512KB二级缓存。耳机缓存保持完全的缓存一致性并为片上每个核提供数据。私有的512KB二级缓存总共构成了容量可达30.5MB的片上缓存。所有的二级缓存由全局分布的 (global-distributed) 标签目录保持完全一致.该内存控制器和 PCIe 客户端逻辑分别向协处理器上的 GDDR5 内存和 PCIe 总线提供一种直接接口。所有这些组件都由环形互连连接在一起。被多个核共享的数据将会被复制到需要使用该数据的核所对应的本地二级缓存中,所以,如果每个核都已完美的同步方式共享相同的代码和数据,则有效的二级缓存容量只有512KB。所以,二级缓存的实际可用容量大小与代码和数据在核与线程间的共享情况密切相关。

协处理器同时支持4KB(标准)、64KB(非标准)和2MB(超大,标准)页面大小的虚拟内存管理。较小页面的访问会带来总体内存映射空间变小以及最快的访问速度。4KB的页面大小长期以来是Linux的标准设置。64KB的页面大小在现有的微处理器并不常见,同时需要Linux核心的特殊支持。2MB大型存储页支持一般是可用的,但是应用程序或运行环境需要经过一些特殊的修改。在访问大数据集和数组时,使用超大页面能够通过提高TLB命中率提升应用性能,这点在应用优化时需要额外注意。

协处理器芯片的每一个核都包含有一个512位宽的SIMD向量处理单元(VPU),并设计了通信向量化指令集。VPU每个时钟周期可同时处理16个单精度(32bit)或8个双精度(64bit)浮点运算。另外,还包含一个扩展数学单元(EMU,Extended Math Unit)用来实现单精度的超越函数指令集,即通过硬件实现指数、对数、倒数和倒数平方根等常用数学运算。

Intel Xeon Phi协处理器主要针对高度并行化的负载优化,同时支持多种常用的编程语言、编程模式和编程工具。除了大量的处理核心,协处理器还包括提供了并行功能的向量处理器单元。此外,协处理器的PCIe接口、DMA、电源管理、传感器以及散热监控等均有各自的设计特点。

软件架构

Intel Xeon Phi协处理器最显著的一个特点是可以启动和运行一个包含网络功能的Linux操作系统,这也是它被成为“协处理器”而非“加速器”(需要依靠主机系统来管理软件应用程序)的主要原因。在协处理器上创建并运行应用程序及系统服务的软件架构包括两个主要部分:

  • 开发工具集和运行时环境: Intel C/C++ Fortran编译器,各种函数库。
  • Intel MPSS(Intel Manycore Platform Software Stack):中间件接口、通信和控制相关的设备驱动,协处理器管理工具以及协处理器操作系统。

MIC的µOS建立的基本执行环境,是其他软件栈的基础。MIC的µOS是基于标准的Linux内核源码。MIC基于Linux的µOS是最小化的,是嵌入式Linux环境通过Linux标准基础(LSB,Linux Standard Base)核心库一直到MIC架构的产物,这也是个未签名的操作系统。µOS提供一些典型的能力,如:进程/任务创建、时序安排、内存管理等。µOS也提供设置、电源和服务器的管理能力。

Intel MPSS提供驱动程序,将PCIe总线映射成一个网络栈中的以太网设备,虚拟化TCP/IP堆栈。系统可以配置桥接TCP/IP网络于所连接的其他网络通信。使用户可以将其作为网络节点直接使用ssh连接到协处理器上。

SCIF(Symmetric Communications Interface)实现了协处理器与主处理器之间,协处理器与协处理器之间的通信。它提供了一个统一的对称的API让主处理器和协处理器通过系统中的PCIe总线进行通信,SCIF可以使协处理器通过DMA方式对大数据块进行高速传输,同时可以将主处理器或协处理器的内存空间映射到任意运行在主处理器和协处理器上的进程地址空间中。

MicAccessAPI是的一组C/C++ API,用于监测和配置Intel Xeon Phi协处理器上的各项参数,如电源管理、CPU使用情况、PCI链路情况等。这些API需要依赖scif库(libscif.so)来实现内核软件栈中的通信。

编程模型

MIC拥有较为灵活的编程方式,MIC卡可以作为一个协处理器存在,也可以被看做是一个独立的节点。host端与MIC端的关系可以组合成一下5种关系。

而实际中的的应用模式通常不会这样复杂,常用的模式分为Native模式和Offload模式。

Native模式所有负载均在MIC端,通常使用于高并行计算程序,程序直接在MIC执行,这种方式对于应用移植来说难度较小,客观限制较多,如内存,第三方库函数等,提升的性能效果也比较有限,在后续的文章中会对此有所分析。

Offload模式是程序主函数由host发起,对于高度并行的计算部分分载到MIC端,由协处理器完成计算后返回结果。这种方式的优点是可以有更为明显的性能提升效果,缺点是移植较为复杂,特别是对于一些数据结构、算法逻辑较为复杂的代码,甚至需要完全重写。

Reference

[1] Jim Jeffers, James Reinders等. Intel Xeon Phi协处理器高性能编程指南[M]. 人民邮电出版社,2014.04

[2] 王恩东, 张清等. MIC高性能计算编程指南[M]. 中国水利水电出版社, 2012.11

[3] George Chrysos. 英特尔® 至强融核™ 协处理器(代号 Knights Corner)[EB/OL]. https://software.intel.com/zh-cn/articles/intel-xeon-phi-coprocessor-codename-knights-corner, 2013.01.15

[4] Intel Developer Zone. Intel Xeon Phi systems software developers guide[EB/OL]. https://software.intel.com/en-us/articles/intel-xeon-phi-coprocessor-system-software-developers-guide, 2012.11.12

[5] Intel Developer Zone. Intel Xeon Phi coprocessor quick start developers guide[EB/OL]. https://software.intel.com/en-us/articles/intel-xeon-phi-coprocessor-developers-quick-start-guide, 2012.11.12

[6] Intel Developer Zone. An overview of programming for Intel Xeon processors and Intel Xeon Phi coprocessors[EB/OL]. https://software.intel.com/en-us/articles/an-overview-of-programming-for-intel-xeon-processors-and-intel-xeon-phi-coprocessors, 2012.11.12

使用rebase修改历史commit

最近在使用gerrit做code review,经常遇到的一个情况是需要更改已经commit的代码。

比如对于如下形式的branch tree:

A -- B -- C -- D  (develop)

问题来了,gerrit上得到了反馈,C上的代码有问题,需要修改。而秉承着“一步一commit“的守则,已经有新的commit提交上去了,目前仓库和远程仓库的HEAD都指向了D。

虽然可以暂时把B merge进去,然后再直接提交一个新commit(E)去修复B上的bug的,但这显然不够优雅,而且把明知道有bug的commit也merge进去本身也是存在风险的,这时,git rebase就派上用场了。

整个主要过程分为四个步骤:

  1. 修改C中的bug,commit到本地repo为E
  2. 输入命令git rebase -i HEAD~3
  3. 根据提示,调整commit顺序,将最新的commit放到C之后,根据提示将pick改为squash,保存退出。(若存在冲突则处理并git add,继续git rebase --continue
  4. git push --force origin develop # 假设目标分支为develop分支

git rebase本来是用来处理分支衍合的,具体原理可以参考官方手册:

http://git-scm.com/book/en/Git-Branching-Rebasing

这里我们实际做的是重新调整合并了当前分支的commit顺序,举个例子:

当前分支名为myrebase,文件rebase_test.py与两个commit相关:

# commit A
print ('hello rebase')
# commit B
print ('bye')

现欲在commit A增加为:

print ('May 18th')

依次做以下操作:

  • 修改rabase_test.py
  • 新提交一个commit C

    git commit -am "fix on commit A"

  • 使用命令

    git rebase -i HEAD~3

-i 表示交互式rebase

HEAD~3 表示对HEAD之前的三次commit进行rebase

也可以使用git rebase -i $commit-id-before-commit-A

其中$commit-id-before-commit-A为commit A之前commit的id,结果如下:

pick 5b55a02 first commit add hello rebase

pick 2f5c48f second commit add bye

pick 225e901 fix on commit A

# Rebase 7f8e5eb..225e901 onto 7f8e5eb

#

# Commands:

# p, pick = use commit

# r, reword = use commit, but edit the commit message

# e, edit = use commit, but stop for amending

# s, squash = use commit, but meld into previous commit

# f, fixup = like “squash”, but discard this commit’s log message

# x, exec = run command (the rest of the line) using shell

#

# These lines can be re-ordered; they are executed from top to bottom.

#

# If you remove a line here THAT COMMIT WILL BE LOST.

#

# However, if you remove everything, the rebase will > be aborted.

#

# Note that empty commits are commented out

  • 根据注释中对各参数的解释,将前三行改为

pick 5b55a02 first commit add hello rebase

squash 225e901 fix on commit A

pick 2f5c48f second commit add bye

  • 若存在冲突,则处理冲突后git commit add .git rebase --continue
  • 由于使用了squash参数,根据提示调整commit信息
  • 看到rebase successful消息后,使用git push --force origin myrebase

整个过程有可能遇到很多问题,要多利用git diffgit log来分析

My First Blog

很久没有写过什么有价值的东西了,当初更新日志的好习惯还是应该保持,不过作为一名技工还是离qq空间之类的东西远一点吧,先用octopress给自己搭一个简单的blog培养一下习惯。

希望能在一年的时间内稍微做出点什么来。

Life is short.
Step by step.
Stay hungry, stay foolish.

See you

import time

if __name__ == '__main__':
    time.sleep(365 * 24 * 3600)