Nova: 虚机的块设备总结 [Nova Instance Block Device]
和物理机一样,虚拟机包括几个重要的部分:CPU、内存、磁盘设备、网络设备等。本文将简要总结虚机磁盘设备有关知识。
1. Nova boot CLI 中有关虚机块设备的几个参数
nova boot CLI 的完整参数如下:
- usage: nova boot [--flavor <flavor>]
- [--image <image>] //boot from image with id
- [--image-with <key=value>] //image metadata properties
- [--boot-volume <volume_id>]
- [--snapshot <snapshot_id>]
- [--block-device-mapping <dev-name=mapping>]
- [--block-device key1=value1[,key2=value2...]]
- [--swap <swap_size>]
- [--ephemeral size=<size>[,format=<format>]]
- [--min-count <number>] [--max-count <number>]
- [--meta <key=value>] [--key-name <key-name>]
- [--file <dst-path=src-path>] //文件注入
- [--user-data <user-data>]
- [--availability-zone <availability-zone>]
- [--security-groups <security-groups>]
- [--hint <key=value>]
- [--nic <net-id=net-uuid,v4-fixed-ip=ip-addr,v6-fixed-ip=ip-addr,port-id=port-uuid>]
- [--config-drive <value>] [--poll]
- <name>
这里面,--boot-volume,--snapshot,--block-device-mapping,--block-device, --swap,--ephemeral 这几个参数都相似的功能。
1.1 --block-device 参数
该参数可以使用下面这些值:
- source=image|snapshot|volume|blank
- dest=volume|local
- id=XXXXXX (a volume|image|snapshot UUID if using source=volume|snapshot|image)
- format=swap|ext4|...|none (to format the image/volume/ephemeral file; defaults to 'none' if omitted)
- bus=ide|usb|virtio|scsi (hypervisor driver chooses a suitable default if omitted)
- device=the desired device name (e.g. /dev/vda, /dev/xda, ...)
- type=disk|cdrom|floppy|mmc (defaults to 'disk' if omitted)
- bootindex=N (where N is any number >= 0, controls the order in which disks are looked at for booting)
- size=NN (where NN is number of GB to create type=emphemeral image, or the size to re-size to for type=glance|cinder)
- shutdown=preserve|remove
这里面只有 source 和 id 是必须的,别的都有默认值。比如:
- --block-device source=image,dest=volume,id=XXXXXXX,bus=ide,bootindex=2
- --block-device source=volume,dest=volume,id=XXXXXXX,bus=ide,type=cdrom,bootdex=1
- --block-device source=blank,dest=local,format=swap,size=50,bus=ide,type=floppy
dest 会指定source 的 destination,包括本地的(local)和 Cinder 卷 (volume)。
dest | source | 说明 | shortcut |
volume | volume | 直接挂载到 compute 节点 | 当 boot_index = 0 时相当于 --boot-volume <volume_id> |
snapshot | 调用 cinder 依据快照创建新卷,挂载到compute节点 | 当 boot_index = 0 时相当于 --snapshot <snapshot_id> | |
image | 调用cinder依据镜像创建新卷,挂载到compute节点 | 当 boot_index = 0 时相当于 --image <image> (Boot from image (creates a new volume)) | |
blank | 通知cinder依大小创建空卷并挂载到compute节点 | ||
local | image |
在 Hypervisor 上创建 ephemeral 分区,将 image 拷贝到里面并启动虚机 |
相当于普通的 Boot from image |
local | blank |
format=swap 时,创建 swap 分区 默认创建 ephemeral 分区 |
当 boot_index=-1, shutdown=remove, format=swap 时相当于 --swap <swap size in MB> 当 boot_index=-1, shutdown=remove 时相当于 --ephemeral |
1.2. 几个 shortcut
2.1 --boot-volume <volume_id>
从 volume Boot 虚机。相当于 --block-device source=volume, dest=volume, boot_index=0, shutdown=preserve。一次只能使用一个 volume。不能和 --image and --snapshot 一起使用。
还可以预先创建好 bootable volume,然后使用 boot-volume 参数来指定该volume id。比如:
- nova boot --flavor 2 --boot-volume f3f00ca1-5683-4e6b-8430-4dba1bbe3e5c boot_from_volume
2.2 --snapshot <snapshot_id>
从 snapshot boot 虚机。相当于 --block-device source=snapshot, dest=volume, boot_index=0, shutdown=preserve。一次只能使用一个 snapshot。不能和 --volumeand --snapshot 一起使用。
2.3 --swap <swap size in MB>
在 boot 虚机的时候增加 swap 块设备。相当于 --block-device source=blank, dest=local, boot_index=-1, shutdown=remove, format=swap。一次只能使用一次。
2.4 --ephemeral size=<size in GB>,format=<ext3, ext4, ...>
在 boot 虚机的时候增加 ephemeral 块设备。相当于 --block-device source=blank, dest=local, boot_index=-1, shutdown=remove。一次可以使用多次该参数。
比如 --ephemeral size=<size in GB>,format=<ext3, ext4, ...>
2.5 --block-device-mapping <dev-name=mapping> 用于增加多个额外的块设备
mapping 的格式是 <dev-name>=<id>:<type>:<size(GB)>:<delete-on-terminate>:
- dev-name: 当 volume 被挂载后在 /dev/dev_name 中的设备名称
- id: volume ID
- type:snap 则volume 是从 snapshot 上创建的;空白
- size (GB): volume 的 size;可以留空白使得Nova自己判断
- delete-on-terminate: True/1 或者 False/0, 标识在 VM 被terminated 后 volume是否被删除
比如从 image boot VM 的同时挂载一个block volume
nova boot --image 4042220e-4f5e-4398-9054-39fbd75a5dd7 --flavor 2 --key-name mykey --block-device-mapping vdc=13:::0 boot-with-vol-test
2.6 --image
指定虚机系统盘的镜像,ID 或者 name。nova compute 会根据 images_type 来决定使用何种类型的系统盘,包括 qcow2(本地镜像文件)、lvm(volume group 中的vol,通过 iSCSI 挂接给虚机)、rbd(ceph rbd volume)等。
2. 虚机的本地磁盘空间
2.1 虚机本地磁盘空间大小设置
在 OpenStack 中, 一个虚机涉及到的存储空间, 主要是 根分区 (/ ,root分区), swap分区, ephemeral disk, 还有就是 Block storage (块存储,OpenStack 中的 Cinder 项目就是用于管理块存储的)。前面三种都是 ephemeral 的 (Nova 中专门定义的 ephemeral disk 指的是除了 root disk 和 swap disk之外的 ephemeral 空间), ephemeral 空间会随着 instance 的生命周期创建和消亡。
- root disk: 根分区,提供boot loader
- swap disk:交换分区。Linux 系统除了必须的 root 分区, 还是用 swap 分区是用于内存耗尽时将物理内存中一部分空间挪到 swap分区中,这样就释放了 一些物理内存空间。
- ephemeral disk:这里说的 ephemeral disk 是狭义的,指除 root 分区和 swap 分区之外, 根据提供的资源状况提供的额外的临时存储。广义的 ephemeral disk 可包括 root 分区和 swap 分区。
Nova flavor 可以定义一个虚机的各分区的大小。以下面的 tiny2 flavor 为例,其 root disk 为 1G 大小,Ephemeral disk 为 1G 大小,Swap disk 为 30M 大小。
- s1@controller:~$ nova flavor-list
- +--------------------------------------+-----------+-----------+------+-----------+------+-------+-------------+-----------+
- | ID | Name | Memory_MB | Disk | Ephemeral | Swap | VCPUs | RXTX_Factor | Is_Public |
- +--------------------------------------+-----------+-----------+------+-----------+------+-------+-------------+-----------+
- | | m1.tiny | | | | | | 1.0 | True |
- | 129f237e--49fa-b489-0e41fb06b70e | tiny2 | | | | | | 1.0 | True |
除了可以在 flavor 中设置各磁盘大小以外, 还使用 nova boot 命令时也可以设置 swap 和 ephemeral 分区的大小和文件系统,只是这里设置的空间大小需要比使用的 flavor 中相应值要小,也可以不设置这两项,不设置的时候会按照flavor的默认值创建, 不然 novaclient 会提示错误。
2.2 虚机中的磁盘
使用 tiny2 flavor 启动虚机后,登录到虚机,使用 “fdisk -l” 命令可以看到其磁盘的情况:
root disk:
ephemeral 和 swap disk:
2.3 当 image type 为 qcow2 时 Nova compute 节点上的磁盘镜像文件
此种类型下,nova compute 会在计算节点本地创建文件夹,并生成虚机系统镜像文件。
对于 libvirt 虚机来说,当虚机是基于镜像启动的时候,虚机的每个磁盘在 nova compute 节点上都有一个磁盘镜像文件,默认是在 /var/lib/nova/instances/<instance_id> 目录中:
- root@compute1:/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b# ls -l
- total
- -rw-r--r-- libvirt-qemu kvm Jun : disk
- -rw-r--r-- libvirt-qemu kvm Jun : disk.local
- -rw-r--r-- libvirt-qemu kvm Jun : disk.swap
每个文件默认都是 qcow2 格式,都使用 backing 文件。
disk 文件对应的是虚机的 root 分区:
- root@compute1:/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b# qemu-img info disk
- image: disk
- file format: qcow2
- virtual size: .0G ( bytes) #受 flavor 指定的大小
- disk size: 1.9M
- cluster_size:
- backing file: /var/lib/nova/instances/_base/fbad3d96a1727069346073e51d5bbb1824e76e34
- Format specific information:
- compat: 1.1
- lazy refcounts: false
而其 backing file 是个 raw 类型的镜像文件:
- root@compute1:/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b# qemu-img info /var/lib/nova/instances/_base/fbad3d96a1727069346073e51d5bbb1824e76e34
- image: /var/lib/nova/instances/_base/fbad3d96a1727069346073e51d5bbb1824e76e34
- file format: raw
- virtual size: 39M ( bytes)
- disk size: 17M
disk.local 是虚机的 ephemeral 分区的镜像文件,默认的时候它同样是 qcow2 类型:
- root@compute1:/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b# qemu-img info disk.local
- image: disk.local
- file format: qcow2
- virtual size: .0G ( bytes)
- disk size: 324K
- cluster_size:
- backing file: /var/lib/nova/instances/_base/ephemeral_1_default
- Format specific information:
- compat: 1.1
- lazy refcounts: false
disk.swap 是虚机的 swap 分区的镜像文件:
- root@compute1:/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b# qemu-img info disk.swap
- image: disk.swap
- file format: qcow2
- virtual size: 30M ( bytes)
- disk size: 196K
- cluster_size:
- backing file: /var/lib/nova/instances/_base/swap_30
- Format specific information:
- compat: 1.1
- lazy refcounts: false
这些磁盘镜像文件是由 Nova 在启动虚机的过程中创建的。镜像文件的目录由 nova.config 的配置项 instances_path 指定,其默认值为 “/var/lib/nova/instances”;镜像文件的 backing 文件的目录由 image_cache_subdirectory_name 配置项指定,其默认值为 “ _base” ,其主要过程可以参考 这篇文章。
libvirt.xml 文件定义了磁盘的镜像文件和磁盘的对应关系:
- <disk type="file" device="disk">
- <driver name="qemu" type="qcow2" cache="none"/>
- <source file="/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b/disk"/>
- <target bus="virtio" dev="vda"/>
- </disk>
- <disk type="file" device="disk">
- <driver name="qemu" type="qcow2" cache="none"/>
- <source file="/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b/disk.local"/>
- <target bus="virtio" dev="vdb"/>
- </disk>
- <disk type="file" device="disk">
- <driver name="qemu" type="qcow2" cache="none"/>
- <source file="/var/lib/nova/instances/eddc46a8-e026-4b2c-af51-dfaa436fcc7b/disk.swap"/>
- <target bus="virtio" dev="vdc"/>
- </disk>
3. Nova 虚机的 block_device_info 数据结构
3.1 代码分析
该数据结构是 Nova 中一个重要的数据结构,它的内容包括虚机的所有磁盘和被附加的所有卷。一个示例如下:
- block_device_info = {
- 'root_device_name': "/dev/sda", //root分区
- 'swap': { // swap 分区
- 'device_name': "/dev/sdb",
- 'swap_size': 5,
- }
- 'ephemerals': [ //ephemerals 分区,可以有多个
- {'num': 0,
- 'virtual_name': 'eph0',
- 'device_name': "/dev/sdc",
- 'size': 5 },
- {'num': 1,
- 'virtual_name': 'eph1',
- 'device_name': "/dev/sdd",
- 'size': 5 },
- {'num': 2,
- 'virtual_name': 'eph2',
- 'device_name': "/dev/sde",
- 'size': 5 },
- ...
- ],
- 'block_device_mapping': [ //block devices mapping,可以有多个
- {'cinfo': {....some cinder volume data....},
- 'mount_device': "/dev/sdf",
- 'delete_on_termination': True },
- {'cinfo': {....some cinder volume data....},
- 'mount_device': "/dev/sdg",
- 'delete_on_termination': True },
- {'cinfo': {....some cinder volume data....},
- 'mount_device': "/dev/sdh",
- 'delete_on_termination': True },
- ...
- ],
- }
block_device_mapping 的信息是由 Nova 在数据库中维护的,数据表是 block_device_mapping,它维护着一个虚机曾经有过但是现在被删除的和现有的卷信息:
MariaDB [nova]> select * from block_device_mapping where instance_uuid='02699155-940f-4401-bc01-36220db80639';
| created_at | updated_at | deleted_at | id | device_name | delete_on_termination | snapshot_id | volume_id | volume_size | no_device | connection_info | instance_uuid | deleted | source_type | destination_type | guest_format | device_type | disk_bus | boot_index | image_id |
+---------------------+---------------------+---------------------+----+-------------+-----------------------+-------------+---------------------------
| 2015-06-10 02:01:56 | 2015-06-10 02:44:31 | NULL | 46 | /dev/vda | 0 | NULL | 26446902-5a56-4c79-b839-a8e13a66dc7a | NULL | NULL | {"driver_volume_type": "iscsi", "serial": "26446902-5a56-4c79-b839-a8e13a66dc7a", "data": {"device_path": "/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-26446902-5a56-4c79-b839-a8e13a66dc7a-lun-1", "host_device": "/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-26446902-5a56-4c79-b839-a8e13a66dc7a-lun-1", "target_discovered": false, "encrypted": false, "qos_specs": null, "target_iqn": "iqn.2010-10.org.openstack:volume-26446902-5a56-4c79-b839-a8e13a66dc7a", "target_portal": "10.0.2.41:3260", "volume_id": "26446902-5a56-4c79-b839-a8e13a66dc7a", "auth_password": "Yeb2Sjit2ESPvkKV7YSs", "target_lun": 1, "access_mode": "rw", "auth_username": "HhADUkXT858xD3AEBhzv", "auth_method": "CHAP"}} | 02699155-940f-4401-bc01-36220db80639 | 0 | volume | volume | NULL | disk | virtio | 0 | NULL |
| 2015-06-10 02:27:06 | NULL | 2015-06-10 02:27:14 | 47 | /dev/vdd | 0 | NULL | 31367039-0da5-4dac-bf9a-40303b869126 | NULL | NULL | NULL | 02699155-940f-4401-bc01-36220db80639 | 47 | volume | volume | NULL | NULL | NULL | NULL | NULL |
| 2015-06-10 02:28:59 | NULL | 2015-06-10 02:29:08 | 48 | /dev/vdd | 0 | NULL | 31367039-0da5-4dac-bf9a-40303b869126 | NULL | NULL | NULL | 02699155-940f-4401-bc01-36220db80639 | 48 | volume | volume | NULL | NULL | NULL | NULL | NULL |
| 2015-06-10 02:30:07 | 2015-06-10 02:44:32 | 2015-06-10 03:58:26 | 49 | /dev/vdd | 0 | NULL | 31367039-0da5-4dac-bf9a-40303b869126 | NULL | NULL | {"driver_volume_type": "iscsi", "serial": "31367039-0da5-4dac-bf9a-40303b869126", "data": {"device_path": "/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-31367039-0da5-4dac-bf9a-40303b869126-lun-1", "host_device": "/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-31367039-0da5-4dac-bf9a-40303b869126-lun-1", "target_discovered": false, "encrypted": false, "qos_specs": null, "target_iqn": "iqn.2010-10.org.openstack:volume-31367039-0da5-4dac-bf9a-40303b869126", "target_portal": "10.0.2.41:3260", "volume_id": "31367039-0da5-4dac-bf9a-40303b869126", "auth_password": "2bUgBWHDTr8HyPBSX7wr", "target_lun": 1, "access_mode": "rw", "auth_username": "FaoWrhsw6CFThDtcUvSf", "auth_method": "CHAP"}} | 02699155-940f-4401-bc01-36220db80639 | 49 | volume | volume | NULL | NULL | NULL | NULL | NULL |
| 2015-06-10 05:51:50 | 2015-06-10 05:51:55 | NULL | 52 | /dev/vdd | 0 | NULL | de127d46-ed92-471d-b18b-e89953c305fd | NULL | NULL | {"driver_volume_type": "iscsi", "serial": "de127d46-ed92-471d-b18b-e89953c305fd", "data": {"access_mode": "rw", "host_device": "/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-de127d46-ed92-471d-b18b-e89953c305fd-lun-1", "target_discovered": false, "encrypted": false, "qos_specs": null, "target_iqn": "iqn.2010-10.org.openstack:volume-de127d46-ed92-471d-b18b-e89953c305fd", "target_portal": "10.0.2.41:3260", "volume_id": "de127d46-ed92-471d-b18b-e89953c305fd", "target_lun": 1, "device_path": "/dev/disk/by-path/ip-10.0.2.41:3260-iscsi-iqn.2010-10.org.openstack:volume-de127d46-ed92-471d-b18b-e89953c305fd-lun-1", "auth_password": "eb6BYxF4oJYLFxDt3woc", "auth_username": "nJPF9yMdy2b9ioobRFMw", "auth_method": "CHAP"}} | 02699155-940f-4401-bc01-36220db80639 | 0 | volume | volume | NULL | NULL | NULL | NULL | NULL |
+---------------------+---------------------+---------------------+----+-------------+-----------------------+-------------+----------------------------+
3.2 实验表明,libvirt 不支持设置 disk 的 device name。
试着使用下面的命令,创建一个 empermeal disk,设置它的 size 为1G:
- nova boot --flavor 5a03775d-11e1-4d20-b4d6-4c54d7036421 --image b07b7e9c-7cb9-4be4-b623-625ef79a142d --block-device source=blank,dest=local,bus=virtio,device=/dev/vdc,size=1 --nic net-id=e088cd37-032c-4ed5--7f4096d2e0eb testdevice2
但是,创建出来的虚机的临时磁盘依然是 /dev/vdb。日志表明libivrt driver 拒绝了用户设置的 device name:
- Compute_service record updated for server-:server-72.2
- -- ::23.830 WARNING nova.virt.libvirt.driver [req-bd][instance: c124e394-cf6f-44ba-be36-53b145067f3c] Ignoring supplied device name: /dev/vdc. Libvirt can't honour user-supplied dev names
分析:
- 这篇文章,https://openstack.nimeyo.com/52423/openstack-dev-nova-device-names-supplied-to-the-boot-request,对此有分析,认为除了 nova xenapi 外,别的 driver 都不支持设置 device name。正是这个 patch,https://review.openstack.org/#/c/189632/,让 libivirt 彻底不支持用户定义的 dev name,但是只是在日志里面报错,而不会让 nova boot 操作失败。
- 但是即使是 xenapi,虽然它能接受用户设置,但这个操作也不一定可靠,也就是nova 不一定会严格按照用户设置的 dev name 来工作。
- 即使 libvirt xml 中有 device name,这个也不一定和虚机实际的磁盘名称是一致的,libvirt 只是维持特定 bus 内的dev names 之间的相对顺序。目前的 linux,会采用 PCI 地址顺序来枚举块设备。这个和我的另一篇文章 识别linux上的设备类型 有些关系。
- 要唯一标示块设备,要么使用 disk serial number(只针对 cinder 卷,nova 会自动生成磁盘序列号),要么使用设备地址信息,可以参考 https://review.openstack.org/#/c/195662/。
另外,要创建临时磁盘的话,需要设置 flavor 的 ephemeral 属性。其值默认为 0,此时无法创建 ephemeral 磁盘。
参考链接:
https://wiki.openstack.org/wiki/BlockDeviceConfig
http://adaishu.blog.163.com/blog/static/175831286201262811249332/
Nova: 虚机的块设备总结 [Nova Instance Block Device]的更多相关文章
- 转 Nova: 虚机的块设备总结 [Nova Instance Block Device]
和物理机一样,虚拟机包括几个重要的部分:CPU.内存.磁盘设备.网络设备等.本文将简要总结虚机磁盘设备有关知识. 1. Nova boot CLI 中有关虚机块设备的几个参数 nova boot CL ...
- Neutron 理解(5):Neutron 是如何向 Nova 虚机分配固定IP地址的 (How Neutron Allocates Fixed IPs to Nova Instance)
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- OpenStack 企业私有云的若干需求(1):Nova 虚机支持 GPU
本系列会介绍OpenStack 企业私有云的几个需求: 自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云( ...
- KVM 介绍(8):使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机 [Nova Libvirt QEMU/KVM Live Migration]
学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分 ...
- KVM(八)使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机
1. QEMU/KVM 迁移的概念 迁移(migration)包括系统整体的迁移和某个工作负载的迁移.系统整理迁移,是将系统上所有软件包括操作系统完全复制到另一个物理机硬件机器上.虚拟化环境中的迁移, ...
- OpenStack企业私有云新需求(1):Nova 虚机支持 GPU
作者:Sammy Liu 刘世民 本系列会介绍OpenStack 企业私有云的几个需求: GPU 支持 自动扩展(Auto-scaling)支持 混合云(Hybrid cloud)支持 物理机(Bar ...
- Neutron 理解 (9): OpenStack 是如何实现 Neutron 网络 和 Nova虚机 防火墙的 [How Nova Implements Security Group and How Neutron Implements Virtual Firewall]
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- openstack nova 虚机镜像后端提取
参考链接:https://www.cnblogs.com/storymedia/p/4500186.html 1.nova 创建的虚机后端目录 其中的base是虚机基础镜像,创建虚机会根据这个基础镜像 ...
- LINUX中块设备文件和字符设备文件的本质区别
在LINUX系统文件类型分类的文章中我们提到了 块设备 和 字符设备文件,那么什么是块设备 字符设备文件呢?他们之间有什么本质上的区别呢? 设备文件分为 Block(块) Device Driver ...
随机推荐
- 图解“管道过滤器模式”应用实例:SOD框架的命令执行管道
管道和过滤器 管道和过滤器是八种体系结构模式之一,这八种体系结构模式是:层.管道和过滤器.黑板.代理者.模型-视图-控制器(MVC) 表示-抽象-控制(PAC).微核.映像. 管道和过滤器适用于需要渐 ...
- C#微信公众平台开发者模式开启代码
using System;using System.IO;using System.Text;using System.Web.Security; namespace HPZJ.Web.sys.exc ...
- 使用 FocusPoint.js 实现图片的响应式裁剪
通常网站的布局都不是单一的.例如图像在电脑.平板和智能手机上可能显示的形状是不同的.特别是如果你使用的是全屏图像,在你必须使用相同的图像文件的情况下,你的主题可能会被截断或完全缺失,或者看起来很尴尬. ...
- Slides - 在线制作效果精美的幻灯片(PPT)
Slides 是可以在浏览器中使用的在线幻灯片编辑器.与传统的演示软件,比如 PowerPoint 相比,Slides 不需要下载任何东西.你所有的信息都是安全地存储在我们的服务器上,无论你在哪里.不 ...
- jQuery立体式数字动态增加(animate方法)
1.HTML结构 <div class="integral">已有<span class="ii"></span>积分< ...
- jQuery原型属性constructor,selector,length,jquery和原型方法size,get,toArray源码分析
首先看一下在jQuery1.7.1中定义的原型属性和方法有哪些? init方法作为实际的构造函数已经详细分析过了,需要了解可以参考http://www.cnblogs.com/yy-hh/p/4492 ...
- bootstrapcss3触屏滑块轮播图
插件描述:bootslider响应bootstrapcss3触屏滑块轮播图 小海已经好久没分享技术性文章了,这个基于bootstrap的触屏版轮播图绝对满足大家的胃口,并且支持移动端触摸滑动.功能上, ...
- 使用js实现带有停顿效果的图片滚动(按钮控制)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 关于SAP的事务提交和回滚(LUW)
1 Sap的更新的类型 在sap中,可以使用CALL FUNCTION ... IN UPDATE TASK将多个数据更新绑定到一个database LUW中.程序使用COMMIT WORK提交修改请 ...
- sharepoint2013的最少下载策略概述(MDS)
该策略是 SharePoint 2013 中的一种新功能,通过在用户导航到新页面时仅发送差异内容来减少页面加载时间. 最少下载策略 (MDS) 是 SharePoint 2013 中的一种新技术,可减 ...