当前位置: 首页 > 科技观察

说说Linux中的进程和线程

时间:2023-03-22 15:07:40 科技观察

Process进程是关于某个数据集,具有某些独立功能的程序。它是操作系统动态执行的基本单位。在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。进程的概念主要有两点:第一,进程是一个实体。每个进程都有自己的地址空间,一般包括文本区(textregion)、数据区(dataregion)和栈(stackregion)。文本区存储处理器执行的代码;数据区存储进程执行期间使用的变量和动态分配的内存;堆栈区存储活动过程调用的指令和局部变量。其次,进程是“执行中的程序”。程序是无生命的实体。只有处理器赋予程序(由操作系统执行)以生命,它才能成为一个活动的实体,我们称之为进程。线程线程是操作系统能够进行操作调度的最小单位。它包含在流程中,是流程中的实际操作单元。线程是指进程中的单个顺序控制流。多个线程可以在一个进程中并发运行,每个线程并行执行不同的任务。在UnixSystemV和SunOS中,也称为轻量级进程(lightweightprocesses),但轻量级进程是指内核线程(kernelthreads),而用户线程(userthreads)则称为线程。进程与线程的关系同一个进程中的多个线程会共享进程中的所有系统资源,如虚拟地址空间、文件描述符、信号处理等。但是同一个进程中的多个线程有自己的调用栈,自己的寄存器上下文,以及自己的线程本地存储。linux中的线程和进程在linux内核中,进程和线程虽然都是任务,但是还是要区分的。其中pid是进程ID,tgid是线程组ID。对于任何进程,如果只有主线程,那么pid就是自己,tgid就是自己,group_leader指向自己。但是,如果一个进程创建了其他线程,情况就会改变。线程有自己的pid,tgid是进程主线程的pid,group_leader指向进程主线程。所以有了tgid,我们就知道tast_struct代表的是进程还是线程。关系如下:图片来源[1]关于线程和进程内核参数的ulimit限制,在linux下执行ulimit-a,会看到ulimit对各种资源的限制。其中,“maxuserprocesses”是一个进程最多可以创建的线程数。我们可以修改这个参数:ulimit-u665352。参数sys.kernel.threads-maxlimit。该参数限制了操作系统全局的线程数,其值可以通过以下命令查看。查看threads-max的方法:cat/proc/sys/kernel/threads-max32768修改该值的方法:#方法一,重启后会失败echo65535>/proc/sys/kernel/threads-max#method2、永久修改echo"kernel.threads-max=65535">>/etc/sysctl.conf3.参数sys.kernel.pid_max限制。该参数限制了操作系统全局的线程数,其值可以通过以下命令查看。这里说一下,32位操作系统的最大值是32768,不能修改,64位系统上pid_max的最大值是2^22。Linux内核在初始化系统时,会根据机器CPU的个数来设置pid_max的值。比如机器的CPU数小于等于32,那么pid_max就会设置为32768(32K);如果机器中的CPU数量大于32,那么pid_max将被设置为N*1024(N是CPU数量)。查看pid_max的方法:cat/proc/sys/kernel/pid_max32768修改该值的方法:#方法一,重启后会失效echo65535>/proc/sys/kernel/pid_max#方法二,永久修改echo"kernel.pid_max=65535">>/etc/sysctl.conf注意:多个线程也会占用一个pid,所以threads-max必须小于等于pid_max。容器线程数的限制对于Linux系统来说,容器就是进程的集合。如果容器中的应用程序创建了太多的进程或者有bug,就会产生类似forkbomb的行为。这样不仅同一节点上的其他容器无法工作,宿主机本身也无法工作。所以对于每个容器,我们需要限制它的最大进程数,而这个功能是由pidsCgroup子系统来完成的。以前遇到过这样的问题,因为java应用要处理很多定时任务,一个定时任务拉起一个线程。但是由于代码有bug,线程没有及时回收,导致容器不断产生线程,耗尽了宿主机的进程表空间,最终导致整个linux上的服务报错“java.lang.OutOfMemoryError:无法创建本机线程”,影响其他服务。创建过程中出现“Resourcetemporaryunavailable”错误。这种问题除了可以让开发者修复bug之外,还需要在系统层面限制线程数。pid在cgroupcgroup中是隔离的。通过改变docker/kubelet的配置,可以限制pid的总数,从而达到限制线程总数的目的。docker,容器启动时设置--pids-limit参数,限制容器级别的pids总数kubelet,开启SupportPodPidsLimit特性,设置--pod-max-pids参数,限制pids总数对于节点的每个pod。原理如下:一个容器建立后,创建容器的服务会在/sys/fs/cgroup/pids下创建一个子目录,这是一个控制组,控制组中最关键的文件就是pids。最大限度。kubelet或者docker向这个文件写入一个值,这个值就是这个容器允许的最大进程数。Kubernetes中的每个节点都会运行一个名为Kubelet的服务,该服务负责节点上容器的状态和生命周期,例如创建和删除容器。根据Kubernetes官方文档ProcessIDLimitsAndReservations,可以设置Kubelet服务的--pod-max-pids配置选项,然后在这个节点上创建的容器最终会使用Cgroupspidcontroller来限制数量容器中的进程。总结Linux中为了防止进程恶意使用资源,系统使用ulimit来限制进程的资源使用(包括文件描述符、线程数、内存大小等)。同样,在容器化场景下,也需要对其系统资源的使用进行限制。Pid是计算机的重要资源,因此在使用时需要对其进行限制,以保证资源的合理利用。dockerd没有默认的pid限制设置;k8s限制了线程数,可以通过在kubelet中启用SupportPodPidsLimit特性来设置pod级别的pid限制。好了,今天的内容就到这里。我是夏老师,祝您今天吃饱饱,下期见。