2012-05-31

img文件挂载方法


在linux中,对于img文件(例如,虚拟机的img文件),有时候需要将其挂载,以便修改其中的内容。能不能将它像iso文件一样挂载呢?
其实方法很简单,只需要两步:
#kpartx -av xxx.img
得到如下信息:
add map loop0p1 ...
此时只需要mount loop0p1即可
#mount /dev/mapper/loop0p1 /mnt
OK,这样就可以进入mnt对img文件的内容进行修改了
要卸载也很简单,同样是两步:
umount /mnt
kpartx -d xxx.img

2012-04-17

你所做过最有效提高编程技能的事情是什么?

 
 

fei 通过 Google 阅读器发送给您的内容:

 
 

于 12-4-16 通过 博客 - 伯乐在线 作者:齐哲

最近在stackexchange网站上看到了一个非常好的问答,有人问:你做过的最有效的提高你的编程水平的一件事情是什么?

回首作为一个程序员这些年来的生活和职业道路,我使用了很多种不同的方法来提高我的编程技能 —— 阅读代码,编写程序,阅读书籍,听讲座,看视频,等等。

我的问题是:你做过的最有效的提高你的编程水平的一件事情是什么?对于那些想提高水平的程序员,你的建议是什么?

我希望你们提供的答案是各种各样的,并且不是那种"放之四海而皆准"的答案 —— 我希望得到适用于不同人的不同的答案。

有很多人给出了自己的答案,在这里,我将其中最受认可的前三种答案选出来翻译给大家。

最受欢迎的回答:学无止境

没有特别的先后次序…

●和比自己更聪明的人一起工作

●永远乐意听取他人的意见,不管对方是低级水平,一般水平,资深,还是大师。职称头衔并不代表一切。

●学习其它的框架/语言,学习它们是的工作原理和思想,拿它们跟你已知的技术做比较。

●学习各种设计模式,最佳实践理论,然后用它们检查自己先前的知识,在需要的时候使用这些模式。

●结对编程

反对Joel说的一切。

第二受欢迎的回答:成为多面手

争取成为一个'多面手万事通'

在我职业生涯的早期,我在一种数据库和编程语言上是个专家。不幸的是,这种数据库在"数据库战争"中落败了,我才发现我的职业道路…很窄。在此之 后,我下定决心以后决不能把自己封在一个小空间里。我开始学习所有手头上能接触到的东 西:Windows,Unix,C,C++,Java,C#,Perl,Python,Access,SQL Server,Oracle,Informix,MySQL,等等。不管什么样的新的,不常见的工具或技术,我都成为"大拿" —— "去问克雷格(作者自己),他要是不会,他会去学会的。"结果,我做了各种各样的项目,从为环境监测做嵌入式系统,到为导弹防御做命令和控制系统。

我在各种的公司里唯一遇到的问题是:它们坚持要把我固定在一个专门的研究方向内,而我的专门研究是要成为一个多面手。[编辑: 也叫做学识渊博的人或多才多艺的人或多领域专家。]

有些事情需要留意 … 高科技界里知识的半衰期是多少?根据摩尔定律(Moore's law):18-24月内,半数你学到的知识都会过时。错误的遵循这种规律的专家会轻易的在这种技术发展的压力崩溃;一个多面手要做的事就是不断的丰富自 己的技能,并从应用这些技能的经历中吸取教训。

第三受欢迎的回答:不要跟臭棋篓子下棋

我一直认为自己在不错的程序员中也算是个"灌篮高手"。直到有个家伙——我们叫他艾伦——被招进团队。艾伦很显然在很多方面都比我优秀。也比我年轻。他让我认识到,在过去的这些年里,我没有多少长进。我是一个特定技术方向的程序员,而且是水平一般。

这惊醒我应该自觉的不断提高自己的水平,特别是我写的代码的水平。

艾伦引导我学会了很多东西。他告诉我,大部分我写的代码在今后的数年里都将一直维护和进行扩展,写代码时要将这点铭记在心。我应该为我的代码写自动 测试程序。艾伦说代码的开发一定不能停止在第一版上,应该不断的重构,提炼,让它达到完美。我发现,我对这些语言和工具的使用都还有还很大的改进空间。

从艾伦那我学到的最重要的一件事情是:永远不要停止学习。

数年后,艾伦离开了公司。我的心里突然感觉空荡荡的。这些年与他为伴让我在技能上提升到了一个全新的水平,我知道现在我比团队里的其他人优秀很多。 他们仍然写着糟糕的代码,犯着以前犯过的错误。我努力教育他们,但他们对此不感兴趣。事实上,他们讨厌有人这样傲慢自大的指出他们犯的错误。

于是,几个月后,我也离开这这个公司。我去了一个很小的公司,在一个很出色的团队里工作。那里每个人都渴望学习更多知识,我喜欢这样的。

我很幸运能遇到艾伦。没有他,我也许现在仍然待在那家死气沉沉的公司和那帮食古不化的家伙在一起,哪都去不了,想的全是自己的私利。

这个讨论在stackexchange网站上的地址是这里

从我个人而言,我觉得第三个答案对我最有价值,不知各位同行们有什么感受?请写在评论里与大家分享。

相关文章


 
 

可从此处完成的操作:

 
 

2012-04-05

xm migrate源码分析

xm migrate源码分析

xen动态迁移虚机的命令为:xm migrate --live <domain id> <destination machine>

迁移的原理

Xen live migration begins by sending a request, or reservation, to the target specifying the resources the migrating domain will need. If the target accepts the request, the source begins the iterative precopy phase of migration. During this step, Xen copies pages of memory over a TCP connection to the destination host. While this is happening, pages that change are marked as dirty and then recopied. The machine iterates this until only very frequently changed pages remain, at which point it begins the stop and copy phase. Now Xen stops the VM and copies over any pages that change too frequently to efficiently copy during the previous phase. In practice, our testing suggests that Xen usually reaches this point after four to eight iterations. Finally the VM starts executing on the new machine.

By default, Xen will iterate up to 29 times and stop if the number of dirty pages falls below a certain threshold. You can specify this threshold and the number of iterations at compile time, but the defaults should work fine.

 


xen动态迁移分为save和restore两部分,先看save部分。

tools/python/xen/xm/migrate.py

该函数主要是对输入的命令作参数解析,然后跳转到
 server.xend.domain.migrate(dom, dst, opts.vals.live,
                                   opts.vals.port,
                                   opts.vals.node,
                                   opts.vals.ssl)
 -->XendDomain.domain_migrate()

tools/python/xen/xend/XendDomain.py


domain_migrate(self, domid, dst, live=False, port=0, node=-1, ssl=None):

1. Make sure vm existing and being running

  dominfo = self.domain_lookup_nr(domid) # get a structure of XendDomainInfo
  if not dominfo:
      raise XendInvalidDomain(str(domid))
  if dominfo.getDomid() == DOM0_ID:
      raise XendError("Cannot migrate privileged domain %s" % domid)
  if dominfo._stateGet() != DOM_STATE_RUNNING:
      raise VMBadState("Domain is not running",
          POWER_STATE_NAMES[DOM_STATE_RUNNING],POWER_STATE_NAMES[dominfo._stateGet()])

2. Notify all device about intention of migration
  
  dominfo.testMigrateDevices(True, dst) 
  ---> XendDomainInfo.migrateDevice(n, c, network, dst, DEV_MIGRATE_TEST, self.getName()) 
  ---> XendDomainInfo.getDeviceController(deviceClass).migrate(deviceConfig,
                                        network, dst, step, domName)
  ---> DevController.migrate()
       由于xoptions.get_external_migration_tool()返回为空,实际上什么也不做,直接返回0
    
   This function is called for 4 steps:

        If step == 0: Check whether the device is ready to be migrated
                      or can at all be migrated; return a '-1' if
                      the device is NOT ready, a '0' otherwise. If it is
                      not ready ( = not possible to migrate this device),
                      migration will not take place.
           step == 1: Called immediately after step 0; migration
                      of the kernel has started;
           step == 2: Called after the suspend has been issued
                      to the domain and the domain is not scheduled anymore.
                      Synchronize with what was started in step 1, if necessary.
                      Now the device should initiate its transfer to the
                      given target. Since there might be more than just
                      one device initiating a migration, this step should
                      put the process performing the transfer into the
                      background and return immediately to achieve as much
                      concurrency as possible.
           step == 3: Synchronize with the migration of the device that
                      was initiated in step 2.
                      Make sure that the migration has finished and only
                      then return from the call.

     这儿DEV_MIGRATE_TEST=0,即步骤0

3. For live migration, make sure there's memory free for enabling shadow mode

   dominfo.checkLiveMigrateMemory()
   --->XendDomainInfo.checkLiveMigrateMemory()
       迁移需要的内存为:1MB per vcpu plus 4Kib/Mib of RAM
       这些内存通过balloon.free(overhead_kb, self)获得

4. 如果使用--ssl选项,则建立SSL连接;否则,建立普通tcp连接

5. 开始迁移

   XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst, node=node)
   --->XendCheckpoint.save()

tools/python/xen/xend/XendCheckPoint.py

def save(fd, dominfo, network, live, dst, checkpoint=False, node=-1)
  
  1. 首先发送SIGNATURE,即LinuxGuestRecord
  2. 为了避免将虚机迁移到本机时虚机重名,将原虚机暂时重命名为migrating-domain_name
  3. 发送配置文件
  4. 真正迁移是在 forkHelper(cmd, fd, saveInputHandler, False)中做的,即创建一个子进程来执行xc_save,而主进程继续执行后面的步骤:

     其中,cmd为 /usr/lib64/xen/bin/xc_save fd domid 0 0 str(int(live)|(int(hvm)<<2))
     (xc_save的参数格式为/usr/lib64/xen/bin/xc_save iofd domid maxit maxf flags

      def saveInputHandler(line, tochild):
            log.debug("In saveInputHandler %s", line)
            if line == "suspend":
                log.debug("Suspending %d ...", dominfo.getDomid())
                dominfo.shutdown('suspend')
                dominfo.waitForSuspend()
            if line in ('suspend', 'suspended'):
                dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP2,
                                       domain_name)
                log.info("Domain %d suspended.", dominfo.getDomid())
                dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP3,
                                       domain_name)
                if hvm:
                    dominfo.image.saveDeviceModel()

            if line == "suspend":
                tochild.write("done\n")
                tochild.flush()
                log.debug('Written done')

  5. 发送qemu设备的状态(即/var/lib/xen/qemu-save.7)
  6. 由于传入的checkpoint参数为True,将suspended的虚机resume
  7. 最后,将重命名的虚机改为原来的名字


下面是restore部分

tools/xen/xend/server/SrvDaemon.py

xend在启动的时候会打开8002端口的监听:
Daemon()-->run()
-->relocate.listenRelocation()
-->tcp.TCPListener(RelocationProtocol, port, interface = interface, hosts_allow = hosts_allow)

相应的参数在xend配置文件中设置:

(xend-relocation-server yes)
(xend-relocation-port 8002)
(xend-relocation-hosts-allow '^localhost$ ^localhost\\.localdomain$')

建立连接后的处理由RelocationProtocol完成,其中最重要的函数为op_receive:
     def op_receive(self, name, _):
        if self.transport:
            self.send_reply(["ready", name])
            try:
                XendDomain.instance().domain_restore_fd(
                    self.transport.sock.fileno(), relocating=True)

            except:
                self.send_error()
                self.close()
        else:
            log.error(name + ": no transport")
            raise XendError(name + ": no transport")

 而XendDomain.domain_restore_fd()是通过XendCheckpoint.restore(self, fd, paused=paused, relocating=relocating)来完成的。

tools/python/xen/xend/XendCheckPoint.py

def restore(xd, fd, dominfo = None, paused = False, relocating = False):
  
  1. 首先接收并验证SIGNATURE
  2. 接收配置文件
  3. 确保本机上没有与要迁移的虚机同名或同UUID的虚机
  4. 根据接收的配置文件建立XendDomainInfo结构:
     
     dominfo = xd.restore_(vmconfig)-->XendDomainInfo.restore(config)

  5. 如果原虚机设置了node_to_cpu,则绑定vcpu到相应的pcpu

  6. 创建image并分配内存(shadow_memory + memory_dynamic_max)

     restore_image = image.create(dominfo, dominfo.info)
     balloon.free(memory + shadow, dominfo)

  7. 真正迁移是在forkHelper(cmd, fd, handler.handler, True)中做的,即创建一个子进程来执行xc_restore,而主进程继续执行后面的步骤:

     其中,cmd为:
     cmd = map(str, [xen.util.auxbin.pathTo(XC_RESTORE),
                        fd, dominfo.getDomid(),
                        store_port, console_port, int(is_hvm), pae, apic])

     (xc_save的参数格式为/usr/lib64/xen/bin/xc_restore iofd domid store_evtchn console_evtchn hvm pae apic

      def handler(self, line, _):
        m = re.match(r"^(store-mfn) (\d+)$", line)
        if m:
            self.store_mfn = int(m.group(2))
        else:
            m = re.match(r"^(console-mfn) (\d+)$", line)
            if m:
                self.console_mfn = int(m.group(2))

  5. 接收qemu设备的状态 (即/var/lib/xen/qemu-save.7)

  6. 设置虚机cpuid,并创建虚机:

        restore_image.setCpuid()
        os.read(fd, 1)           # Wait for source to close connection
        dominfo.completeRestore(handler.store_mfn, handler.console_mfn):
        self._introduceDomain()
        self.image = image.create(self, self.info)
        if self.image:
            self.image.createDeviceModel(True)
        self._storeDomDetails()
        self._registerWatches()
        self.refreshShutdown()

  7. 最后,启动虚机:

     dominfo.waitForDevices()
     dominfo.unpause()

xc_save和xc_restore的源码

暂时还没有仔细看。


2012-03-31

最少编码原则

 
 

Sent to you by fei via Google Reader:

 
 

via 博客 - 伯乐在线 by 童海波 on 3/30/12

本文作者是一位资深软件工程师,他根据多年的编程经验,把自己的观点组织整理成本文,希望能给大家一点启发。

"最少编码原则"并不是说写的代码少到令意思表达不清楚。其实在很多情况下,可以只写几行代码就能执行相同的逻辑,但这对于后来接手的开发者来说是非常棘手的。最少编码不只是写最少量的代码,还意味着优雅的代码。如果你是有经验的程序员,可能就会明白我将要说什么了。本文的目的是尝试着去阐述清楚这个原则,虽然程序员们都听过都了解该原则,却很少能在每天的工作中将其运用起来。

最少编码指的是代码不仅仅全面解决了问题,而且除了执行能够准确地解决问题的逻辑行,没有其他多余的行。代码要尽可能普通,简单的代码也是优雅的代码,程序员看到这样的代码会感到愉悦。

最少编码和设计良好的解决方案之间有着密切的关系,优秀的解决方案可以大大减少代码量。使用组态代码(不同功能的代码可以很容易地组合)以及减低代码行或逻辑之间的耦合度,就是很好的代码设计例子,同时也符合最少编码原则。

将一段代码转换成最少代码就是我们通常所说的重构,重构可以删掉多余的不必要的部分,精简代码。

大量的代码需要执行大量的逻辑,很容易造成 bug。没有写出来的代码才没有 bug,只要在编辑器中输入了字符,那么 bug 也可能潜伏在其中。重点是,如果代码不是特别繁琐,那么潜在的 bug 也会相应减少,最少编码原则可以将出现 bug 的可能性降到最低。

如何写出最少代码?通常在写代码前要进行代码设计,而不是一来就开始敲代码,这是毋庸置疑的。简单的、通用的逻辑能减少代码量。对第一稿代码运用代码重构可以使代码简练,将最终版本转化为优雅的解决方案等,这都遵循了最少编码的原则。其实反复思考以及不断运用最少编码原则能够使任何垃圾代码变得优雅。

原文链接:Principle of least coding

相关文章


 
 

Things you can do from here:

 
 

你的代码(软件)安全吗?

 
 

Sent to you by fei via Google Reader:

 
 

via 博客 - 伯乐在线 by 童海波 on 3/31/12

2011年安全事件层出不穷,几乎可以称为"黑客年"。以前黑客通常是利用程序漏洞来造成破坏,令网站陷入尴尬的境地,但如今他们却是为了窃取数据、IP 地址,或者通过在网站中植入木马将恶意软件安装到访客的电脑里,更有甚者转移账户、违反行业规定等等,因此应用程序的安全显得越来越重要。

安全漏洞 TOP5

据统计,10个程序中有 8 个以上在第一次测试时都不能通过 OWASP(Open Web Application Security Project,开放式 Web 应用程序安全项目)的检查,而且有一半的开发者在基础程序安全评估中都只能获得C级甚至更低的评级。

下图展示了排名前五位的安全漏洞。其中橙色表示受影响的 Web 应用的比例,XSS 最高;蓝色表示被黑客利用的比例,SQL 注入的比例最高。

你的代码(软件)安全吗?

编程语言中的安全漏洞

下图展示了一些流行的编程语言中比例最高的 3 种安全漏洞。其中 XSS 的威胁依然很高,而信息泄露和加密问题也不容忽视。

你的代码(软件)安全吗?

你的代码(软件)安全吗?

不同开发模式的安全漏洞

下图展示了各种开发模式(内部开发、商业项目、开源项目)所带来的安全漏洞,其中 XSS 高居榜首。

你的代码(软件)安全吗?

首次提交 OWASP 测试的合格率

下图展示了内部项目、商业项目、开源项目、外包项目、综合开发项目在首次提交 OWASP 测试的合格率,其中内部项目最高,外包项目最低。

你的代码(软件)安全吗?

Android 应用也不安全

Android 应用的安全问题主要有两类:一类是加密问题,另一类是信息泄露问题。加密问题中 61% 是缺乏熵编码的问题,这通常是由于在 Java 程序中使用统计 RNG 而不用加密 RNG 所致。而这些问题用一行代码就能修复。

你的代码(软件)安全吗?

修复安全问题所需时间

其中外包项目中的安全问题通常能在一周之内修复,其次是开源项目。而其他项目的修复周期相对来说比较长一些。

你的代码(软件)安全吗?

如何增强程序安全性?

● 及时更新软件。自己编写安全的软件或要求供应商及时修复安全问题。

● 不断学习。自学巩固程序安全基础知识,参加培训班。

● 要求供应商为其软件提供安全保证。要求供应商查看程序代码,在合同里写入安全保证条款。

原文链接:Are You Practicing Safe Coding?

相关文章


 
 

Things you can do from here:

 
 

开发笔记(16) : Timer 和异步事件

 
 

Sent to you by fei via Google Reader:

 
 

via IT牛人博客聚合网站 by 云风 on 3/31/12

这几天,安排新来的王同学做数据持久化工作。一开始他是将 sharedb 里的数据序列化为文本储存的。这步工作做完后,开始动手把数据放到 Redis 数据库中。我们的系统主干由 Lua 构建,所以需要一个 Lua 的 Redis 库。google 来的那份,王同学不满意。三下五除二自己重写了一个。据说把代码量减少到了原来的三分之一(开源计划我正在督促)。唯一的问题是,如果直接采用系统的 socket 库,不能很好的嵌入我们的整个通讯框架。我们的 skynet 全部是通过异步 IO 自己调度的,如果这个数据服务单方面阻塞了进程,会使得别的进程获得不了时间片。

蜗牛同学打算改进 skynet 增加异步 IO 的支持。

我今天在考虑现有的 API 时候,对比原有的 timer 接口和打算新增加的异步 IO 接口,发现它们其实是同一类东西。即,都是一个异步事件。由客户准备好一类请求,绑定一个 session id 。当这个事件发生后,skynet 将这个 session id 推送回来,通知这个事件已经发生。

在用户编写的代码的执行序上,异步 IO 和 RPC 调用一样,虽然底层通过消息驱动回调机制转了一大圈,但主干上的逻辑执行次序是连续的。

受历史影响,我之前在封装 Timer 的时候,受到历史经验的影响,简单的做了个 lua 内 callback 的封装。今天仔细考虑后发现,我们整个系统不应该存在任何显式的回调机制。正确的接口应该保持和异步 IO 一致:

每个独立服务有一组信息包的分发器,外部来的消息会被并发的处理,每条消息是一个独立的执行序,相互不会被阻塞。同时,服务本身有一个主干执行流程,在启动之初就开始执行,可以认为它响应了一个启动消息。btw, 启动消息同时可以看成是热更新的重启消息。

无论是主干执行序还是其它消息的响应函数,它们都可以在里面调用一个叫 sleep 的函数。这其实就是用底层的 timer 回调实现的。调用的时候,当前执行序会被调度器挂起,直到 skynet 计量指定的时间长度后,重新从这个断点继续执行。

这样做,隐藏了 timer callback 的细节,隐藏了异步性。用户也很难主动的并发出多条并行的执行序来,可以减少系统复杂性。

热更新该怎样做呢?

我希望是在更更新时,收到热更新消息后,只是在系统里设置了一个标记。然后在主干代码中,合适的位置去检查这个标记位,体面的结束。这比较像 C 语言中处理中断信号的手法。比简单粗暴的杀掉注册的 timer 更为合理。

ps. 前两天碰到了服务相互依赖性的问题。需要主动在启动流程中提示,依赖哪个服务先启动。也就是有个服务启动管理器的服务,响应服务启动的消息,以及提供 RPC 调用,可以在一个服务启动后,返回成功信号。


 
 

Things you can do from here: