array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 Docker学习总结(一)—— namespace,cgroup机制 - 爱码网

1.namespace:

  Linux Namespaces机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace。每个

Namespace里面的资源对其他Namespace都是不可见的,要创建新的Namespace,只需要在调用clone时指定相应的flag。Linux

Namespaces机制为实现基于容器的虚拟化技术提供了很好的基础,容器正是利用这一特性实现了资源的隔离。不同container内的

进程属于不同的Namespace,彼此透明,互不干扰。

  Linux很早就实现了一个系统调用chroot,该系统调用能够为进程提供一个限制的文件系统。chroot提供了一种简单的隔离模式:chroot

内部的文件系统无法访问外部的内容。Linux Namespace在此基础上,提供了对UTS、IPC、mount、PID、network的隔离机制。

  UTS: 包含了运行内核的名称,版本,底层体系结构的信息

  IPC: 包含了所有与进程间通信有关的信息

  PID: 就是进程ID

  mount: 包含了文件系统的视图

  NET: 网络访问

  1.1 task_struct中的结构:
struct task_struct { 
... 
struct nsproxy *nsproxy; 
... 
};

 

<——————将给定进程关联到所属的各个命名空间——————>
struct nsproxy { 
atomic_t count; 
struct uts_namespace *uts_ns; 
struct ipc_namespace *ipc_ns; 
struct mnt_namespace *mnt_ns; 
struct pid_namespace *pid_ns; 
struct net *net_ns; 
}; 

1.2 创建命名空间的方式

  1.2.1. clone创建新进程时,可以设置选项,使新进程与父进程共享命名空间,还是新进程创建一个独立的命名空间.

  1.2.2. unshare系统调用,可以将进程的某些部分从父进程分离,其中也包括命名空间。

1.3 PID

  PID命名空间按层次组织,在创建一个新的pid namespace,该命名空间中所有的pid都对父命名空间可见,但是子命名空间

看不到父命名空间的pid,因此进程在不同的pid namespace中具有不同的pid,只要能看到该进程的namespace都有一个PID。

  对于所有的进程来说,都有两种ID:一个是全局的ID(包含PID、TGID、PGRP、SID),保存在task_struct->pid中;

另一个是局部的ID,即属于某个特定的命名空间的ID,对应task_struct->pids数组,可以通过task_struct->pids[pid_type]->pid

来找到对应的pid结构。pid_type:PIDTYPE_PID,PIDTYPE_PGID,PIDTYPE_SID,PIDTYPE_MAX

struct pid 

atomic_t count; //计数
unsigned int level; //对应多少namespace
struct hlist_head tasks[PIDTYPE_MAX]; //指回task_struct
struct rcu_head rcu; //rcu是将所有struct pid组织起来的辅助结构
struct upid numbers[1]; //numbers成员中存储的是struct upid结构,该结构是pid与pid_namespace相关联的结构。
}

upid
struct upid { 
int nr; 
struct pid_namespace *ns; 
struct hlist_node pid_chain; 
};

所有的upid都保存在一个散列表中,通过upid->pid_chain组织。

static struct hlist_head *pidhash;
};
pid_namespace
struct pid_namespace { 
struct kref kref; 
struct pidmap pidmap[PIDMAP_ENTRIES]; //保存该namespace中pid的分配情况
int last_pid; //保存上一个分配的pid
struct task_struct *child_reaper; //每个namespace都有一个进程来扮演Linux中init进程的角色,child_reaper指向这个进程
struct kmem_cache *pid_cachep; 
unsigned int level; //表示该namespace在整个命名空间的层次
struct pid_namespace *parent; //父namespace
struct vfsmount *proc_mnt; 
struct bsd_acct_struct *bacct; 
};

 

2.cgroups:限制被namespaces隔离起来的资源,为资源设置权重,计算使用量,操控任务启停。

  特点:cgroups通过伪文件系统方式实现

             组织管理操作单元细粒度到线程级别,用户也可以创建销毁cgroup实现资源再分配

            资源管理的功能都已子系统方式实现,接口统一

            子任务创建之初与副任务同出一个cgroups

  作用:资源限制:对任务使用的资源总额进行限制

             优先级分配:通过分配CPU时间片,IO带宽等来控制任务优先级

             资源统计:CPU使用时长,内存用量等

             任务控制:任务挂起,恢复等

  相互关系:  cgroups具有层级结构,每个层级通过绑定对应的子系统进行资源控制,cgoups层级可以包含0或1个子节点。子节点继承

父节点挂载的子系统。

  1.一个子系统能附加到多个层级,前提是目标层级只有唯一一个子系统

  2.一个层级可以附加多个子系统

  3.一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层级。

  4.系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在 cgroup 的成员。然后可根据需要将该子任务移动到不

同的 cgroup 中,但开始时它总是继承其父任务的cgroup。

   Cgroups子系统:

    blkio -- 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等)。

    cpu -- 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问。

    cpuacct -- 这个子系统自动生成 cgroup 中任务所使用的 CPU 报告。

    cpuset -- 这个子系统为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。

    devices -- 这个子系统可允许或者拒绝 cgroup 中的任务访问设备。

    freezer -- 这个子系统挂起或者恢复 cgroup 中的任务。

    memory -- 这个子系统设定 cgroup 中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。

    net_cls -- 这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包。

     ns -- 名称空间子系统。  

  cgroups数据结构:

task_struct中与cgroups有关的:

    struct css_set *cgroups;

    struct list_head cg_list;

其中cgroups指针指向了一个css_set结构,而css_set存储了与进程相关的cgroups信息。cg_list是一个list_head结构,用于将连到同一个css_set的进程组织成一个链表。

struct css_set {

    atomic_t refcount; //该css_set的引用数

    struct hlist_node hlist; //用于把所有css_set组织成一个hash表,这样内核可以快速查找特定的css_set

    struct list_head tasks; //指向所有连到此css_set的进程连成的链表

    struct list_head cg_links; //指向一个由struct cg_cgroup_link连成的链表

    struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; //subsys是一个数组,存储一组指向cgroup_subsys_state的指针。

};

一个cgroup_subsys_state就是进程与一个特定子系统相关的信息。通过这个指针数组,进程就可以获得相应的cgroups控制信息了

struct cgroup_subsys_state {

    struct cgroup *cgroup;

    atomic_t refcnt;

    unsigned long flags;

    struct css_id *id;

};

    cgroup指针指向了一个cgroup结构,也就是进程属于的cgroup。进程受到子系统的控制,实际上是通过加入到特定的cgroup实现的,因为cgroup在特定的层级上,而子系统又是附加到层级上的。通过以上三个结构,进程就可以和cgroup连接起来了:task_struct->css_set->cgroup_subsys_state->cgroup。

    cgroup和css_set是一个多对多的关系,一个进程对应一个css_set,一个css_set就存储了一组进程(有可能被几个进程共享)跟各个子系统相关的信息,而且一个进程可以同时属于几个cgroup,只要这些cgroup不在同一个层级。一个cgroup中可以有多个进程,而且这些进程的css_set不一定都相同,因为有些进程可能还加入了其他cgroup。

struct cg_cgroup_link {

    struct list_head cgrp_link_list;

    struct cgroup *cgrp; 

    struct list_head cg_link_list;

    struct css_set *cg;

};

   cg_cgroup_link作为一个中间结构将 cgroup和css_set联系起来,cgrp_link_list和cg_link_list分别指向cgroup和css_set所在的链表。每个进程都会指向一个css_set,与这个css_set关联的所有进程都会链入到css_set->tasks链表,cgroup通过中间结构cg_cgroup_link来寻找所有与之关联的所有css_set,从而可以得到与cgroup关联的所有进程。

  mount -t cgroup 查看当前系统所有根层级,进入到跟层级目录下,mkdir [名称]就可以创建一个cgroup,新创建的cgroup下的tasks文件为空的,表示当前cgroup无进程,根层级目录下的tasks文件内包含当前系统所有进程。

相关文章: