Just For Coding

Keep learning, keep living …

Celery实例介绍

Celery是一个基于消息传递的分布式任务队列。与单纯的消息队列相比较,队列中传递的消息为任务(Task/Job)信息,而不是数据类信息,Celery基于这些消息完成了任务信息的管理。实现这种任务管理的相似项目还有Gearman,只不过这个项目已经很久未更新了,更推荐使用Celery。

Celery支持同步和异步执行两种模式。同步模式为任务调用方等待任务执行完成,这种方式等同于RPC(Remote Procedure Call), 异步方式为任务在后台执行,调用方调用后就去做其他工作,之后再根据需要来查看任务结果。Celery自己没有实现消息队列,而是直接已存在的消息队列作为Broker角色。官方推荐的Broker为RabbitMQ,除此之外,Redis、Beanstalkd、MongoDB等也都支持,具体可参考官方文档

Celery整体架构可以理解为下图:

D-BUS API查找与调用

上篇文章<<D-Bus实例介绍>>中简要介绍了D-Bus的基本概念,其中提到systemdNetworkManager等系统服务导出了D-Bus API供其他程序来调用。本文通过示例来说明这些API的查找与调用。

上篇文章我们提到D-Busobject可以实现多个InterfaceD-Bus规范中标准化了一些接口,这些接口对于我们调用其他服务提供的D-Bus API非常有帮助。

我们主要来看其中的两个:

它有一个方法:

1
org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data)

它会返回一个包含有对象(object), 接口(interface), 方法(methods), 信号(signals),属性(properties)等信息的XML字符串。对象如果实现这个接口, 我们就可以通过调用该方法了解这个对象对外提供的所有信息。

XML字符串的解析方法可以参考官方文档: https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format

D-Bus实例介绍

D-BusLinux及其他类UNIX系统上的一种IPC(Interprocess communication)机制。相较于传统的管道(PIPE)Socket等原生基于字节流的IPC方式,D-Bus提供了基于独立Message的传输方式,应用程序使用起来更加简单。D-Bus的设计初衷是为Linux桌面环境上的一系列应用程序提供通信方式,它的设计里保留了许多对上层框架设计考虑的元素。

D-Bus的常用架构与传统的Socket一对一通信模式不同,它基于中间消息路由转发的模式来实现, 如下图:

虚拟机KPTI性能影响分析

Meltdown漏洞暴发之后,各云厂商已陆陆续续升级宿主机,升级Guest是否有较大的性能影响, 是否应该升级Guest虚拟机等问题又困扰着云租户们。

本文基于实例来分析Guest虚拟机的性能影响。

首先来看Meltdown的原理。现代CPU架构在不同的安全等级运行指令。内核需要直接操作硬件,运行于最高权限,而几乎所有的应用程序都运行于各低权限上。用户态进程通过系统调用访问内核数据。一般情况下,CPU在执行时使用虚拟内存地址,内核使用页表来控制虚拟内存与物理内存的映射。用户态进程不能访问映射给内核的内存页。这些映射关系的计算较为耗时,因而CPU使用TLB(Translation lookaside buffer)来存储计算后的映射关系。从TLB中移除这些映射再重新计算并缓存会消耗性能,因而内核实现上会尽可能减少刷新TLB,于是内核将用户态和内核的数据都映射进用户态页表中。正常情况下,这不存在安全风险,页表的权限可以阻止用户态进程访问内核数据。

VMware vSphere平台下API操作虚拟交换机及虚拟接口

之前的文章<<VMware vSphere东西向网络防护>>介绍了在VMware vSphere平台上如何通过操作虚拟交换机及虚拟接口来实现二层网络的微隔离。本文通过代码实例来说明调用API实现其中涉及的相关操作。

我们使用VMware官方的Python SDK来实现,SDK地址如下:

首先使用pip安装pyvmomi, 这里我们使用支持vSphere6.5的版本:

1
pip install pyvmomi==6.5.0.2017.5-1

下面介绍使用Python SDK的基本流程。

OpenvSwitch端口镜像

之前的文章<<VMware vSphere平台端口镜像>>介绍了VMware vSphere环境下虚拟交换机的端口镜像机制,本文来介绍在OpenvSwitch环境中如何实现端口镜像。

OVS上实现端口镜像的基本流程如下:

  • 创建mirror,在mirror中指定镜像数据源及镜像目的地
  • 将创建的mirror应用到bridge

镜像数据源可以通过下面几个选项来指定:

  • select_all: 布尔值,设置为true时,进出该mirror所生效的bridge上的每个数据包都将被镜像
  • select_dst_port: 从该port离开虚拟交换机的数据包将会被镜像,从Guest角度看是Guest网络接口的流入方向
  • select_src_port: 从该port进入虚拟交换机的数据包将会被镜像,从Guest角度看是Guest网络接口的流出方向
  • select_vlan: 指定特定VLAN做为数据源,整个VLAN的数据包都会镜像到目的地

镜像目的地可以用下面选项来指定:

  • output_port: 将数据包镜像到特定的port
  • output_vlan: 将数据包镜像到指定VLAN, 原始数据的VLAN tag会被剥掉。若镜像多个VLAN到同一个VLAN,没有办法区分镜像后的数据包来源于哪个VLAN。

Libvirt和QEMU Hook机制介绍

在我们的QEMU/KVM虚拟化环境中,当所有的虚拟机启动时需要自动添加一个ivshmem设备,用于虚拟机与宿主机之间通信。为了添加该设备,我们需要在调用QEMU时,添加上ivshmem设备的相关参数,例如:

1
-device ivshmem,shm=fg_i3,size=8m,bus=pci.0,addr=0x1f

Libvirt使用XML文件来定义虚拟机配置,并根据XML文件来生成QEMU命令行参数,进而执行QEMU程序来启动虚拟机实例。我们可以在所有虚拟机的XML文件的<devices>节点中添加上<shmem>配置,如:

1
2
3
4
5
<shmem name="fg_i3">
    <model type="ivshmem" />
    <size unit='M'>8</size>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x0' />
</shmem>

这样,libvirt启用QEMU实例时,则会添加如下参数:

1
-device ivshmem,id=shmem0,size=8m,shm=fg_i3,bus=pci.0,addr=0x1f

Guest启动后,登录查看PCI设备,可以看到相应的ivshmem设备:

QEMU Monitor机制实例分析

QEMU实例运行时,用户可以通过monitor机制来与实例进行交互,通过它可以获取当前运行的虚拟机信息,处理热插拔设备,管理虚拟机快照等。要了解全部能力,可以参考文档: https://qemu.weilnetz.de/doc/qemu-doc.html#pcsys_005fmonitor

QEMU启动时,需要使用-monitor选项指定做为console设备,官方文档说明如下:

1
2
-monitor dev
    Redirect the monitor to host device dev (same devices as the serial port). The default device is vc in graphical mode and stdio in non graphical mode. Use -monitor none to disable the default monitor.

下面首先以标准输入输出设备做为console来启动QEMU实例:

1
2
3
4
[root@localhost ~]# qemu-system-x86_64 cirros-0.3.5-x86_64-disk.img -smp 2,cores=2 -m 2G -vnc :20 -device virtio-net-pci,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -name vm0 -monitor stdio

QEMU 2.0.0 monitor - type 'help' for more information
(qemu)

console里可以输入相关命令来完成我们的操作,比如我们查看虚拟机网络设备状态:

1
2
3
(qemu) info network
virtio-net-pci.0: index=0,type=nic,model=virtio-net-pci,macaddr=52:54:00:12:34:56
 \ net0: index=0,type=tap,ifname=tap0,script=no,downscript=no