上回说到,小E发现了为什么鹿晗和吴亦凡谈恋爱还没有导致新某某博服务器挂掉的秘密(划掉,文末再讲)Linux下的三个秘密,可以让同一台Linux服务器上,混部不同业务的服务进程,并且避免发生网络Socket端口,CPU与RAM资源,以及其他资源权限的三大冲突。
第一个秘密是namespace。
namespace从字面上可以翻译为“命名空间”。顾名思义地,namespace是用来从name层面,把整个系统划分为不同的space的。如果两个进程在不同的namespace,它们是相互感知不到对方的存在的,也不能通过操作系统内置的IPC等方式通信。
让我们举一个栗子。
如果鹿晗和吴亦凡(两个进程)上初二的时候就出现了早恋的倾向,在课堂上当众手拉手(出现了不应当有的进程间通信),被校长知道了,会把两个人分到不同的班(使用namespace隔离),这样,鹿晗所在的班上没有名叫吴亦凡的学生(namespace隔离下,进程找不到对方的pid),两个人就无法在课堂上手拉手了(namespace隔离禁止了进程间的通信)。
当然,在Linux下,namespace不只可以用来隔离进程。
我们在Linux源代码中的nsproxy.h 里面可以看到这么一段:
(链接:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/nsproxy.h?h=v5.16.5 )
代码语言:javascript复制struct mnt_namespace;
struct uts_namespace;
struct ipc_namespace;
struct pid_namespace;
struct cgroup_namespace;
struct fs_struct;
/*
* A structure to contain pointers to all per-process
* namespaces - fs (mount), uts, network, sysvipc, etc.
*
* The pid namespace is an exception -- it's accessed using
* task_active_pid_ns. The pid namespace here is the
* namespace that children will use.
*
* 'count' is the number of tasks holding a reference.
* The count for each namespace, then, will be the number
* of nsproxies pointing to it, not the number of tasks.
*
* The nsproxy is shared by tasks which share all namespaces.
* As soon as a single namespace is cloned or unshared, the
* nsproxy is copied.
*/
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_for_children;
struct net *net_ns;
struct time_namespace *time_ns;
struct time_namespace *time_ns_for_children;
struct cgroup_namespace *cgroup_ns;
};
extern struct nsproxy init_nsproxy;
如上面的代码中所示,namespace实际上有六种:
- uts_namespace, 隔离的是UNIX Time-sharing System,虽然名字上写的是time-sharing,但实际上是用于隔离主机名和域名,为一台linux服务器虚拟出不同的主机名和域名;
- user_namespace, 可以用于隔离用户ID,用户组ID,不同root的目录以及key等;
- ipc_namespace, 顾名思义是用来隔离操作系统signal、共享内存或其他IPC消息的;
- mnt_namespace, 用来隔离文件系统挂载点,也就是实现对文件系统做隔离;
- pid_namespace,隔离pid,也就是隔离不同进程;
- net_namespace,隔离网络。关于network namespace,我们在前面其实已经介绍过,见这里:《云计算与虚拟化硬核技术内幕 (14) —— 不忘初心,删繁就简》
通过这六种namespace,就可以实现各个进程之间的隔离,其安全程度实质上和虚拟机之间的隔离是等价的:
内存隔离:KVM隔离和namespace隔离实质上都是进程隔离(每个VM是QEMU的一个进程),操作系统从CPU的MMU硬件层面保证了被隔离的实例之间无法互访对方内存;
网络隔离:KVM隔离的虚拟机网络和namespace隔离的Linux网络,实质上都是通过Linux的network namespace实现的;
存储隔离:KVM隔离的虚拟机通过QEMU的VirtIO挂载不同的虚拟盘实现存储隔离,其安全性和mnt namespace基本同等;
这样,就解决了同一Linux服务器上混部多个服务进程实例可能造成的冲突问题;
第二个秘密是CGroups。
CGroups是Control Groups的简称,能够精确控制某一进程占用的CPU和RAM资源数量。比如,在某一配置了32vCPU(HT),128GB RAM的Linux服务器上混部了一个Web服务,一个JVM和一个数据库服务,操作系统就可以通过CGroup将CPU和RAM资源精确地分配给这三个不同的任务。
CGroups有一系列子系统,如cpu,memory,blkio,ns等,能够限制Linux操作系统中的进程使用的CPU、内存、块存储IO和系统namespace资源。
我们在前文《虚拟化与云计算技术硬核内幕 (20) —— 时间管理大师(下)》中提到过,操作系统可以为虚拟机分配vCPU和RAM,如QEMU中的一个线程,就是对应VM中的一个vCPU,将该线程单独绑定在某个硬件HT上,也就是将物理HT分配给了VM。如果将两个或多个QEMU线程绑定在一个硬件HT上,就是所谓的超分配(overscription)。
这种超分配,在CGroups中的实现则不同。如果需要把2个进程混部在同一个vCPU上,可以通过修改进程的CGropus限制,来实现限制进程在某个vCPU上,并限制其占用CPU的配额。由于Linux的时间片分配单位为0.001s (1ms),因此,CPU配额最小分配的颗粒度也不能低于1ms。
第三个秘密叫做unionfs。——这个留到下期再讲。我们先聊一下段子:
上期说到,
有一天,歌手陈某某(就是被石景山区群众举报溜冰的那个家伙),发了一条长某博,内容是自己离婚了。很快,新某某博的服务器就挂掉了。
运维团队紧急排查,发现原来是评论过多,而每条长某博及评论都放在redis里面,通过这条长某博的id,进行哈希后送去对应的redis分片。这样,如果某条长某博评论量过大,redis被过多的写请求打死,相应的APP就只能返回http 503了。
从此以后,新某某博的长某博都被改成了图片方式发布,这样可以放到对象存储里面,并通过CDN帮忙挡刀,redis的根据评论的时间戳进行分片。
这么做以后,新某某博就拍着胸脯说:即使有5个明星同时出轨或者离婚,我们也可以顶住!
后来,设计这个架构的大哥L,成为了方老师的同事,大家如果想成为L团队的一员,可以在下期关注方老师在公众号推送的招聘JD!