本月月末启动人生当中的第三次找工作,在此记录一下找工作当中遇到的问题,加深自己对这些问题的理解。
目标岗位: Python后台开发
2018-12-27,一个做企业内部管理系统的小公司
问题1: 我们的Web Server是如何将每一个Request交到对应的线程去做处理的?
我的回答是Server后台会有IO复用的机制,如果每个request代表一个IO链接的话,它会去监控哪些IO链接有数据收发,当它切换到状态活跃的链接时,就相当于交到对应的线程了;
这个回答我觉得并不准确,线程在IOLoop上面必然存在一个标识的,文件描述符对应一个Socket,而线程必然有一个线程id来标识线程;
以当前我比较了解的Tornado为例,其实对于高并发的场景来说,多线程只是用来分离耗时操作的一个手段,所有的请求会经过HTTPServer处理后走到对应的Handler,我们在Handler处理过程当中会去创建一个线程池,然后执行耗时操作的时候会单独起一个线程来执行这个操作(具体的内部实现就是创建一个worker, 同时创建一个与这个worker绑定的Future对象,然后将这个worker加入线程池的queue当中去,以及使用IOLoop的add_callback将其添加);
其实Tornado是一个单线程的框架,不存在后台需要去路由某一个Request到对应线程的情况
问题2: 在我们的部署服务器上面,有可能出现很多tcp链接为time_wait状态,这一般会是因为什么原因引起的?
我的回答一顿胡扯,说什么time_wait都是服务器上面出现的。。。
首先这个问题看过很多遍了,但是其实自己在应用当中一次都没有处理过类似的问题
先来复习一下TCP的状态图:
主动发起关闭的一方会先发一个FIN,之后等待收到ACK以及FIN之后变为TIME_WAIT状态,TIME_WAIT状态会持续2MSL,MSL为报文的最大生存时间(TTL),一般会是在1-4分钟;
在典型的TCP模型当中,主动断链是由客户端发起的(服务端作为被动响应方),但是对于大量短连接的web服务器来说,还是有可能出现大量的TIME_WAIT的,因为对于短连接,我们会执行finish方法,主动将请求关闭;这种情况下,一般的教程会建议修改内核参数(re_use, 增加端口范围等)
问题3: MySQL事务之间存在哪几种锁?
我的回答:我记得有4中锁的状态,具体怎么记不清楚了。。
回答不准确,准确的说是4种隔离方式,同时这里问的是事务的锁,但是感觉这个说法也不严谨,最准确的说应该是MySQL引擎的锁,而事务使用了这些锁实现了4种隔离机制;
MySQL的锁:
- 表级锁: 针对整张表加锁
- 行级锁: 针对一行数据加锁
- 页面锁: 介于表锁和行锁之间
MyISAM的锁: - 表共享读锁: 支持多个请求对同一个表单进行读操作,但是无法让其他请求进行写操作
- 表独占写锁: 无法让其他请求对表进行读和写的操作
具体的应用就是MyISAM会针对Select加读锁,而对于Update、Insert、Delete加写锁,同时写锁的优先级高于读锁(所以MyISAM不适合于大量更新和频繁查询的场景,更新会抢占查询,让查询变得很慢)
InnoDB的锁:
InnoDB支持事务,同时支持行锁
四种隔离机制:
- Read uncommitted: 可以读到其它事务未提交的数据
- Read committed: 只能读到其它事务已经提交的数据
- Repeatable read: 读到的内容都是事务开始时候的状态,所以支持重复读取,会获取同样的结果
- Serializable: 每次读都获取表级共享锁,各个事务之间完全串行化执行
问题4: 在python当中一般如何实现单例模式?
- 在Class定义的地方创建一个实例,然后每次使用都是import这个实例过去
- 使用装饰器(闭包)的方式,在闭包内使用一个局部变量来存储实例,每次从这个变量里面拿实例
- 还可以使用元编程的方式实现,在想要实现单例的Class当中定义一个metaclass,在metaclass当中存在一个类变量保存创建好的一个class object
问题5: 有没有了解过python3当中的异步实现语法?
async+await, 之前是通过其他库来实现协程的,python3.5增加了这两个关键字,结合eventloop实现针对协程的原生支持
async声明一个函数为协程,await表示一个动作为阻塞,将其加入eventloop,在执行完毕之后再返回
问题6: 描述一下new和init的区别
new用于创建类,init用于创建实例,call则每次在实例被调用的时候执行
问题7: 有没有研究过python当中的metaclass
python当中变量、函数、类都是对象,而metaclass就是创建类的类;
在python当中有一个type方法,使用type(class_name, referred_class, **kwargs),可以创建一个类,并定义好类的一些属性,在一般class的定义当中,解释器会去寻找是否针对metaclass有定义,如果有的话会使用metaclass来创建class,如果没有声明的话去模块内寻找是否有metaclass,如果还没有的话则会使用type方法来创建一个class
问题8: 对于python当中的yield语法,使用它有什么好处?
yield关键字定义了一个方法为生成器,生成器可以返回yield后的值同时下一次从yield之后的语句执行
典型的应用就是配合后台事件循环机制作为协程使用,协程需要程序员控制切换,而这些都可以通过yield的声明来显示的定义
问题9: 讲解一下对于python当中多进程、多线程、协程的理解
CPU密集:多进程
高并发: IO复用机制+异步+协程; 其中异步通过回调函数、yield+多线程的方式实现
问题10: 讲解一下IO复用技术有哪几种,它们之间有何区别
select: 将用户空间的fd(用于描述Socket链接)拷贝到内核空间,遍历所有fd,针对有数据收发的Socket进程处理
poll: 基本实现和select类似,但增加了最大fd个数的限制(select为单个进程最大1024)
epoll(kqueue): 不用每次都去拷贝所有fd到内核空间,同时只处理状态活跃(就绪)的fd,epoll会针对每个fd绑定回调函数
问题11: 描述一下你对于关系型数据库和非关系数据库的理解
关系型数据库代表MySQL: 有清晰的数据结构定义,对于多表关联查询支持比较好,但是在应付大数据场景有点力不从心(巨量小结构的数据,并且需要良好的扩展性能)
非关系型数据库代表MongoDB: 不需要定义数据结构,数据都是在通过键值对的方式存储的,对于多键值对关联查询也有支持但是不如关系型数据库(支持aggregation),扩展性较好
当前我自己的应用场景均为涉及到要考虑这两者原生缺陷的地步,所以我觉得都可以用,但是还是推荐优先使用关系型数据库
2018-1-2, 一个做车联网的公司:
问题1: 当前你们项目当中对于用户认证是怎么做的呢?
其实现在做的两个项目里面压根儿就没做用户的认证,直接前端弄了一套单点登录,后台默认能访问到请求方法的时候就已经是通过了认证的了
实际上当前用的Tornado框架针对认证是有一套完整的方法处理的,可以为当前的请求对象添加cookie,添加好了cookie之后,返回的时候将cookie返回给浏览器,cookie最终被存储在浏览器一侧,后面用户再发起请求的时候,就可以先使用get_cookie判断请求是否有携带cookie过来,从而判断是否对用户进行登录认证或者是直接引导至接口方法
cookie是存储在客户端的,典型的cookie内容包括expire、domain、expire、secure、http-only
- expire:声明这个cookie的有效时间
- domain、path:一起构成了这个cookie能够被使用的url
- secure:一般表示cookie只能通过安全的方式去传输,比如通过https
- http-only:表示cookie无法被客户端获取,比如无法被js获取,只能被服务端修改
问题2: 对于Python3当中的eventloop有多少了解?
当前基本上对于它没有了解,因为还没开始用python3
但是对于它,需要知道的就是这个应该算是python自带的后台时间循环系统,对比python2,当前我主要用的都是tornado的IOLoop,而且可以看到Salt-stack后台用的也是tornado的IOLoop;
后面研究一下eventloop的源码,以及事件驱动模式的设计原理(已经找了一篇文章了)
问题3: 对于不可变对象的id判断
这个问题的关键是理解,对于简单数据类型,str以及int,python内部有一个小数据池
就是str、int对象在一定范围内,创建的对象都是指向同一个内存地址
对于int,范围为-5至256
对于str,范围为不超过20字节,并且字符串中不能出现特殊符号以及空格
问题4: 在不新增List的情况下,实现List的去重
当时的思路是首先对list进行排序,然后再对list进行遍历,在遍历过程当中把重复的元素扔到List末尾去
但是写的时候发现,扔的过程当中List的当前遍历的index是不断发生变化的,这种情况下就需要使用两个指针了,一个指向当前识别的重复元素,一个指针来进行遍历,在发生元素移动的时候,两个指针都要一定变动
问题5: 简单说一下对于数据库锁的理解,以及典型的互斥锁场景
这个问题我回答上了MyISAM和InnoDB的锁的区别,比如InnoDB支持行锁,支持事务
但是对于两个锁互斥的场景说不清楚,之前的确也没有处理过这样的问题
其实一个典型的互斥场景:
有两个线程A和B,他们都要对table_0和table_1两张表操作,此时A正在对table_0进行读写,并且对table_0加了锁,同时B对table_1进行读写,B对table_1加了锁,这个时候A又要去访问table_1的资源或者B又要去访问table_0的资源,因为表已经被锁了,所以它们获取不到资源,而只能相互等待,而这种等待是没有意义的,除非一方放弃锁,否则双方都进行不了下一步操作,这个时候就可以视作一种互斥的场景
而解决互斥锁一个最简单的方法就是把其中一方进行回滚,比如回滚A,A将会释放针对table_0加上的锁,从而B可以获取table_0的资源,之后B执行完成,释放掉table_1的资源,从而A能够重新发起执行成功
2018-1-19, 一个做云计算的公司(主要做微服务后台开发以及中间件容器):
问题1: 结合with...as...使用的方法内部必须要实现哪两种函数?
这个问题最初我回答的是。。yield和close,我现在只用过一次with...as...,用来操作数据库session的
正确答案是enter和exit方法
最典型的with as场景是open一个file的场景,with open("file_path") as f:
with主要做两件事情,首先调用f对象的enter方法,最后在语句执行完成之后调用f对象的exit方法;
如果我们要自己写一个上下文管理器,可以使用@contextmanager装饰器来定义函数,从contextmanager的代码中我们可以看到,装饰器返回了一个生成器方法,将我们被装饰的函数封装成了一个generator,而这个生成器对象内部有enter与exit方法的定义,分别为generator的next以及next.next;
所以我们在使用contextmanager的时候可以在被装饰方法内部使用yield语句构造为一个生成器,首先返回我们要使用的对象,最后再执行对象关闭的操作;
def contextmanager(func):
@wraps(func)
def helper(*args, **kwds):
return _GeneratorContextManager(func, args, kwds)
return helper
def __enter__(self):
try:
return next(self.gen)
except StopIteration:
raise RuntimeError("generator didn't yield") from None
def __exit__(self, type, value, traceback):
if type is None:
try:
next(self.gen)
except StopIteration:
return False
else:
raise RuntimeError("generator didn't stop")
contextmanager典型用法:
def session_scope():
#setup动作,获取将要操作的对象
session = db.get_session()
try:
# yield后的对象作为contextmanager_generator内的__enter__方法返回
yield session
# 调用contextmanager_generator内的__exit__方法执行yield之后的语句
session.commit()
except Exception:
session.rollback()
finally:
session.close()
问题2: 随机生成指定长度的字符串密码,并且需要针对密码的格式做判断
一道笔试的编程题,要求随机生成指定长度的包括大小写字母、数字的随机字符串;
我只写了如何生成随机字符串,并没有去检查格式,要求一定要由小写字母、大写字母、数字组成
后面可以补加一个正则判断,re.match(r"[0-9]", seq) and re.match(r"[a-z]", seq) and re.match(r"[A-Z]", seq), 如果不符合这个的话则重新获取随机字符串
问题3: python当中一些字符串的内置方法,除了strip、split、index之外
最最常用的:
- string.upper()
- string.lower()
- string.find('', beg, end)
- string.count()
- string.replace()
问题4: Docker容器之间的几种网络通信模式,这些通信模式对应了现实当中的哪些网络设备?
其实仔细想一想,也就两种通信方式,一种是同一台宿主机上面的不同容器之间通信,这种通信方式默认是可以通信的,因为Container创建的时候,默认就会在Docker engine的brige上面创建了一个映射端口,并且为container分配IP地址,这个brige相当于一个二层的交换机能够满足容器之间相互进行通信;
另外一种情况是不同宿主机之间的容器的通信,这个我认为有两种方式,一种是正常做端口映射,然后容器之间的通信相当于两台宿主机之间特定的端口通信;另外一个就是通过overlayer的方式通信了,这个需要配置docker network,相当于在宿主机之间配置一个虚拟的路由器
问题5: 如何对Docker容器的资源做限制,比如不让一个容器无限制的申请宿主机的资源?
这个问题我的回答是运行容器的时候配置特性的用户,不让它有root权限从而使它无法无限制申请资源,其实这个问题最标准的答案是在运行容器的时候加上一些限制的参数,比如docker run 后面跟一个-cpus可以限制容器能使用的cpu核数,跟一个-m参数可以设置容器使用的内存大小,同时可以设置一些IO速度上面的限制
问题6: 写Dockerfile的一些基础语法
- FROM: 声明容器的基础镜像repository
- ENV: 声明一个变量,后续变量使用{}来引用
- ADD/COPY: 本质上干的事情是一样的都是从源地址把文件弄进容器内,只是ADD的功能要强一些,比如可以从url获取文件放入容器,以及可以将压缩文件解压放入容器路径下,而COPY则单纯的只是拷贝文件
- RUN: 在容器当中执行的命令,每执行一条命令,相当于给镜像加了一个新的层
- CMD: 定义在docker run的时候默认执行的命令,当docker run后面主动有声明执行命令的话,则这个语句不生效
问题7: 一些典型的网络传输协议,针对了解的几种讲一讲
待回答
问题8: 一般机房当中的存储设备,需要考虑的关键点是什么?存储设备与计算设备之间传输协议是用的什么?
SCSI, SAS
问题9: 了解MongoDB、Redis的集群部署方式么?有哪几种
MongoDB:
- Replica Set: 主节点存储数据,备节点存储数据,同时还有一个仲裁节点(在主节点挂了之后选举一个备节点来替换主节点)
- Sharding: Client链接集群会先到一个路由节点,每个数据节点(主-备节点)都会有对应的配置节点,路由节点先路由到对应的配置节点之后再去访问具体的数据节点,这里面也存在仲裁节点
- Master-Slave: 传统的主-备节点模式
问题10: 讲一讲Django内部的Route原理
问题11: 讲一讲Java的Hash map和Hash Table之间的区别
大哥,这个问题我真的不会啊,Java我满打满算写了有2周时间吧
最核心的区别应该是这个:Hashmap是基于Hashtable的轻量级实现,hashtable是synchronized(线程安全),而hashmap不是
而ConcurrentHashMap是基于Hashmap的优化数据结构,能保证线程安全
问题12: 一句话介绍云计算
虚拟化计算机资源提供服务,包括IaaS,PaaS,SaaS
问题13: 一句话介绍微服务
SOA(Service Oriented Architecture),将大产品的各个模块服务化,保证各个微服务可以持续开发、测试、演进,并且拥有良好的弹性(健壮性、扩展性)
问题14: 对于HTTP2.0有了解么?
Http2.0最主要的改进:
- 传输内容非文本,采用二进制传输
- 采用多通道传输,而非http1.0的流水线或者多连接的方式
- 服务端可以主动推送响应至客户端
- 采用的新的压缩技术压缩报头,提高传输效率
问题15: 对于进程间通信有了解么? 共享内存是什么数据都可以共享吗?
进程间通信的方式:
- 管道
- 信号量
- 共享内存
- 消息队列
问题16: 在Linux当中一个进程最多启动多少个线程? 这个参数是在哪里配置?
一个进程能够启动的线程数量是由当前进程的资源所决定的,例如在32位的Linux上面,一个进程可以获得的最大用户内存空间为3GB,单个线程的默认栈空间为8M,所以最多可以创建3072/8=384个线程
然后可以通过修改默认的线程栈大小来调整最大线程数目,这个可以通过命令ulimit -s来设置
具体的配置文件在etc/security/limits.conf
2019-2-13, 一个做金融后台数据处理的公司
问题1: new和init的区别
问题2: python如何处理大文件
问题3: 字典的key和value对调
问题4: 微服务挂了如何监控,日志如何监控
问题5: Mysql InnoDB的隔离等级有哪几个?默认的隔离等级是什么?
问题6: Mysql里面的ACID是什么?
问题7: Mysql索引的数据结构是怎么样的?
问题8: Docker的CMD和Entrypoint命令有何区别?
网友评论