为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!
这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。
本份面试集锦涵盖了
- 174 道运维工程师面试题
- 128道k8s面试题
- 108道shell脚本面试题
- 200道Linux面试题
- 51道docker面试题
- 35道Jenkis面试题
- 78道MongoDB面试题
- 17道ansible面试题
- 60道dubbo面试题
- 53道kafka面试
- 18道mysql面试题
- 40道nginx面试题
- 77道redis面试题
- 28道zookeeper
总计 1000+ 道面试题, 内容 又全含金量又高
- 174道运维工程师面试题
1、什么是运维?
2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?
3、现在给你三百台服务器,你怎么对他们进行管理?
4、简述raid0 raid1raid5二种工作模式的工作原理及特点
5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?
6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
运行结果图
分析:
gcc -o 编译完成后,./+可执行文件名执行后,多次重复执行,观察到每次结果都有所不同,for循环时操作系统的调用次序不同,显示的结果也不同。接着之前的分析,我们在调用fork()函数后可能每次执行都是父或子进程先执行,这也许会给我们制造一些困惑,难道我的程序出错了?难道书上讲错了?
当然不是,之所以实验一我们总看到父进程先执行,那是因为我们的程序执行太简单了!!!
每个进程就执行一个printf()这当然不合理,说明不了什么问题,所以基于这个问题,这次我将用一个for循环对每个进程的输出多执行几次,当然我们也可以用while(1)来一直执行,那样结果更加明显,当然最好设置一个键盘响应函数让按下某个键后可以退出。
从我执行得到的结果可以看出,现在,parent,duaghter,son的执行顺序就是随机的, 可能前一秒操作系统还在执行parent进程里面的代码,后一秒他就变了,开始执行son,或者duaghter里面的代码了。
实验进行到这我们也就可以更加深刻的了解fork()函数的来龙去脉了吧!
想要更加深入的了解fork()函数的使用可以参考网上的各种博客上关于fork()函数的解析!!!
实验三:在调用exec()函数用新的程序替换该子进程的内容,并利用wait()函数来控制进程执行的顺序。调用exit()函数使子进程结束。
在fork后的子进程中使用exec函数族,可以装入和运行其它程序;
exec()函数说明:
实际上在Linux中,并不存在一个exec()的函数形式,exec指的是一组函数,一共有6个,分别是:
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg, …, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
(百度百科上解释)为防止大家对exec()函数族理解出错。
这些函数具体用法大家可以亲自尝试一下,网上都有各种说明,在这不做过多说明;
在Linux中使用exec函数族主要有一下两种情况:
1,当进程认为自己不能再为系统和用户做出任何贡献调用exec函数族让自己重生;
2,进程需要执行另一个程序。
wait()函数:
原理:进程一旦调用了wait,就立即阻塞自己,当分析到当前进程的子进程已经exit,便会收集这个子进程的信息,然后彻底销毁,如果没有找到这样的子进程,就会一直阻塞在这里,直到有一个出现。
在这里我调用execl()函数列出了路径为/bin/下的文件信息;两个子进程各自调用一次。
代码部分:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
pid_t pid1,pid2; //进程标识符
pid1 = fork(); //创建一个新的进程
if(pid1<0)
{
printf("创建进程失败!");
exit(1);
}
else if(pid1==0) //如果pid为0则表示当前执行的是子进程
{
printf("子进程1,我将调用exec函数,进程标识符是%d\n",getpid());
execl("/bin/ls","ls","-1","-color",NULL);
printf("exec failed!\n");
exit(1);
}
else //否则为父进程
{
pid2 = fork();//創建一個新的進
if(pid2<0)
{
printf("创建进程失败!");
exit(1);
}
else if(pid2==0) //如果pid为0则表示当前执行的是子进程
{
printf("进程2,我将调用exec函数,进程标识符是%d\n",getpid());
execl("/bin/ls","ls","-1","-color",NULL);
printf("exec failed!\n");
exit(1);
}
else //否则为父进程
{
wait(NULL);
printf("父进程,进程标识符是%d\n",getpid());
printf("完成!\n");
exit(0);
}
}
return 0;
}
运行结果:
分析:
可以看出在使用了exec()函数后程序使用了ls的命令,列出/bin/目录下的文件信息,执行完execl()函数后,子进程调用exit()函数,退出当前进程,而我们可以发现在使用wait()函数后,父进程永远将在其他的子进程完成之后才执行,所以在输出的结果中我们可以看到最后输出的将是父进程的信息。
实验四:利用Linux的信号量机制实现生产者消费者问题(基于进程)。
目的:利用生产者消费者问题更加深刻的理解进程同步与互斥的实现。
几个函数简介:
pthread_create():
函数简介
pthread_create是UNIX环境创建线程函数
头文件
#include<pthread.h>
函数声明
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);
返回值
若成功则返回0,否则返回出错编号
参数
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的地址。
最后一个参数是运行函数的参数。
pthread_join():
函数简介
函数pthread_join用来等待一个线程的结束。
函数原型为:
extern int pthread_join __P (pthread_t __th, void **__thread_return);
参数:
第一个参数为被等待的线程标识符
第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。
注意
这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。如果执行成功,将返回0,如果失败则返回一个错误号。
signal():
SIGINT这个信号是在用户在控制台输入Ctrl+C的时候进程收到的。
signal(SIGINT, &sig_int);这一句指定了收到了SIGINT这个信号以后,处理函数是sig_int
只要在10秒内输入Ctrl+C,屏幕上会打印出"Catch a termination single."
在程序中我用signal()函数作为结束程序的函数按下Ctrl+C退出程序。****
sleep():
就是挂起进程指定的秒数,时间到了返回0。这个函数是我们调节生产者消费者生产和消费能力强弱的函数。
有关信号量sem_t,以及信号量的各个函数的使用的简介可以参考一下博客https://blog.csdn.net/evsqiezi/article/details/8061176
代码部分:
生产者生产过程:
producer()
{
while(生产未完成)
{
.
.
.
生产一个产品;
P(empty)
P(mutex);
送一个产品到有界缓冲区;
v(mutex);
v(full);
}
}
消费者消费过程:
consumer()
{
while(还要继续消费)
{
P(full)
P(mutex);
从有界缓冲区取走产品;
v(mutex);
v(empty);
.
.
.
消费一个产品;
}
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include<signal.h>
#define producer_N 4//生产者数量
#define consumer_N 5//消费者数量
#define Buffer_N 9//缓冲区大小
int producer_id=0;//生产者ID
int consumer_id=0;//消费者ID
int in=0;//消费者放取产品的位置
int out=0;//消费者放取产品的位置
int Buffer[Buffer_N];//缓冲区
sem_t sem_empty;//同步信号量
sem_t sem_full;//同步信号量
pthread_mutex_t mutex;//互斥信号量
void Signal_print(int signo);//处理信号
void print(); //打印缓冲队列
void *producer();//生产者
void *consumer();//消费者
void main()
{
pthread_t m_producer[producer_N];
pthread_t m_consumer[consumer_N];
int i,ret1[producer_N],ret2[consumer_N];
printf("生产者数目都为4,消费者数目为5,产品缓冲为9,生产者每3秒生产一个产品,消费者每6秒消费一个产品,Ctrl+c退出程序\n");
if(signal(SIGINT,Signal_print)==SIG_ERR)
printf("error signal!\n");
int ru1=sem_init(&sem_empty,0,Buffer_N);//初始化有界缓冲区大小
int ru2=sem_init(&sem_full,0,0);//初始化满缓冲区大小
if(ru1||ru2)
{
printf("error init signal!");
exit(0);
}
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
出程序\n");
if(signal(SIGINT,Signal_print)==SIG_ERR)
printf("error signal!\n");
int ru1=sem_init(&sem_empty,0,Buffer_N);//初始化有界缓冲区大小
int ru2=sem_init(&sem_full,0,0);//初始化满缓冲区大小
if(ru1||ru2)
{
printf("error init signal!");
exit(0);
}
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**