1. 服务器处理并发请求有哪几种方式?
- 单线程 Web 服务器:服务器一次只处理一个请求,处理完再处理下一个。实现简单,但性能较低,无法同时处理多个客户端请求。适合学习或低并发场景。
- 多进程 / 多线程 Web 服务器:服务器通过创建多个进程或线程来并行处理多个请求。可以是“请求到来时动态创建”,也可以是“预先创建固定数量的进程/线程池”。并发能力强,但每个请求绑定一个进程/线程,当并发量非常大时,系统资源开销大,线程/进程上下文切换代价高。
- I/O多路复用 Web 服务器:服务器使用如
select、poll、epoll
等机制,在单线程中同时监听多个客户端连接。一旦某个连接有事件,就触发处理逻辑,不阻塞其他请求。典型代表:Nginx,适合处理大量并发连接,尤其是 I/O 密集型任务。- 多路复用 + 多线程/多进程 混合架构:将多路复用和多线程/多进程结合。比如多个工作进程,每个进程内部用 epoll 实现事件驱动,每个请求用线程处理业务逻辑。兼顾高并发和多核 CPU 利用率,负载均衡效果好。高性能 Web 框架(如 Netty、OpenResty)常用这种方式。
2. 讲一下select,poll,epoll的区别?
- select:是最早的 I/O 多路复用机制。通过一个固定大小的 fd 集合(通常是 1024)来监听多个文件描述符(Socket)。每次调用 select 时,都需要将整个 fd 集合从用户态拷贝到内核态,内核遍历每个 fd 检查是否有事件发生,返回后用户也要再遍历一遍。
- poll:是对 select 的改进,没有了最大 fd 数量限制。使用链表结构存储 fd,因此理论上可以监听任意数量的 fd。但本质机制和 select 一样,每次都要遍历整个 fd 列表,性能也会随着连接数线性下降。
- epoll(Linux持有):是 Linux 2.6 引入的高性能 I/O 多路复用机制,专门为大规模并发连接(C10K)设计。epoll 使用红黑树保存所有监听的 fd,只需要注册一次,不需要每次传整个集合。内核中维护一个就绪链表,当某个客户端发来消息,内核会把这个事件放进“就绪链表”中(只记录发生事件的 fd),调用
epoll_wait()
只返回发生事件的 fd 列表。
特性 | select | poll | epoll |
---|---|---|---|
支持连接数量 | 有上限(一般 1024) | 无限制 | 无限制 |
数据结构 | 数组 | 链表 | 红黑树 + 就绪链表 |
是否每次传入 fd 集 | 是 | 是 | 否(注册一次即可) |
是否全量遍历 | 是 | 是 | 否(只返回就绪 fd) |
内核拷贝效率 | 低 | 低 | 高(避免重复拷贝) |
性能 | 差(线性下降) | 中 | 高(适合高并发) |
3. https是如何防范中间人的攻击?
中间人攻击是指攻击者悄悄截获并篡改用户与服务器之间的通信内容,让双方都以为自己在和对方通信,但实际上都在和"中间人”通信。
比如:你在登录银行网站(https://abc-bank.com)时:如果使用的是 HTTP,攻击者可以劫持 Wi-Fi,把你请求的内容“拦截 + 修改”:把你要访问的银行页面换成他伪造的钓鱼页面;把你输的账号密码收走,然后再转发到银行,模拟你登录。你毫不知情。、
HTTPS = HTTP + SSL/TLS,SSL/TLS协议提供了三个关键保障:身份认证 + 加密通信 + 完整性校验:
假设你访问 https://abc-bank.com,客户端是浏览器,服务器是银行服务器。
- 客户端发起请求:浏览器向服务器发起 TLS 握手请求。包含:支持的加密算法、随机数(Client Random)等。
- 服务器返回证书:会返回自己的数字证书(通常是 X.509 格式);包括域名信息、公钥、有效期、由权威 CA 机构签名。
- 客户端验证证书有效性(身份认证):客户端会验证证书是否过期,防止老证书被滥用;是否由受信任 CA 签发,阻止伪造证书;是否和访问域名匹配,防止证书劫持比如冒充 abc-bank.com);签名是否可验证,使用 CA 公钥验证签名,确保证书没被篡改。如果验证失败,浏览器会弹出红色警告页面,不允许你继续访问(例如“您的连接不是私密连接”)。
- 协商加密密钥(防止窃听):浏览器通过公钥加密或 Diffie-Hellman 协议,与服务器协商出一个对称加密的 session key(会话密钥)。即使中间人截获整个握手过程,也无法算出密钥(因为缺少私钥),后续通信使用这个密钥进行对称加密,性能高,且安全。
- 后续通信(数据完整性):每条消息都会带上一个完整性校验码(如 HMAC 或 MAC),收到数据后,双方都用 session key 验证 HMAC 是否一致,如果中间人偷偷该动内容,校验就会失败,连接会被关闭。
4. 描述一下打开百度首页后发生的网络过程?
当我在浏览器地址栏输入 https://www.baidu.com 并回车后,浏览器首先检查本地缓存和 DNS 缓存,若无有效缓存,则发起 DNS 查询,逐级解析出百度服务器的 IP 地址;接着浏览器与该 IP 通过三次握手建立 TCP 连接,然后进行 TLS 握手,验证服务器数字证书的合法性并协商出对称加密密钥,保障后续通信安全;握手完成后,浏览器发送加密的 HTTPS GET 请求请求首页资源,服务器响应 HTML 内容后,浏览器开始解析 HTML,同时发现的 CSS、JavaScript、图片等资源会并发发起新的请求;所有资源加载完成后,浏览器构建 DOM 树和 CSSOM 树,合成渲染树,进行布局和绘制,最终将百度首页完整渲染呈现给用户;在此过程中,TLS 加密确保数据传输安全,HTTP 协议保证请求响应的可靠性,而浏览器多线程并发请求和渲染机制保证了页面加载的效率和流畅体验。
5. 什么是ddos攻击?怎么防范?
DDoS(Distributed Denial of Service,分布式拒绝服务攻击)是一种利用大量分布在全球各地的被攻击者控制的“僵尸网络”(Botnet)发起的攻击。攻击者通过这些大量被感染的设备,向目标服务器或网络持续发送海量请求或流量,耗尽目标的计算资源、带宽或服务能力,导致服务器无法正常响应合法用户的请求,最终造成服务中断或者严重性能下降。相比单点的DoS攻击,DDoS攻击的流量更大、来源更分散,防御更为复杂。
DDoS攻击的主要类型:
- 流量型攻击(Volumetric Attack):大量无用流量淹没网络带宽,如UDP洪水、ICMP洪水。
- 协议型攻击(Protocol Attack):消耗服务器资源或防火墙状态表资源,如SYN洪水、Ping of Death。
- 应用层攻击(Application Layer Attack):针对具体应用,消耗服务器计算资源,如HTTP洪水、慢速POST攻击。
如何防范DDoS攻击?
- 部署流量清洗设备
利用防火墙、入侵检测系统(IDS)、入侵防御系统(IPS)和专业的DDoS清洗设备,实时检测异常流量,自动过滤和丢弃恶意流量,保证正常流量通行。- 使用内容分发网络(CDN)和云防护服务
通过CDN将流量分散到全球各节点,利用云服务提供的弹性扩展能力吸收和分散攻击流量,避免单点过载。比如阿里云、AWS Shield、Cloudflare等提供的DDoS防护解决方案。- 合理设计网络架构
采用多链路、多数据中心的冗余架构,负载均衡分配请求,避免单点瓶颈,提高系统的抗压能力。- 访问控制与限流
对客户端IP进行频率限制,限制每个IP单位时间内的请求数,防止攻击流量集中;使用黑白名单管理,阻断已知恶意IP。- 应用层防护
针对HTTP/HTTPS应用,使用验证码、人机验证、行为分析等技术过滤异常请求,防止应用层攻击。- 提前演练与监控
实时监控流量和系统性能,设置告警机制;定期进行DDoS防护演练,完善应急响应流程。
6. Java有哪些常用的锁,在什么场景下使用?
- 内置锁(synchronized):
synchronized
是最基础的锁机制,JVM 层面实现,自动加锁解锁,支持重入。它通常用于保护临界区,保证同一时刻只有一个线程访问共享资源。
场景:适合保护简单方法或代码块的线程安全,比如计数器、对象状态同步。缺点是功能较简单,不能中断等待或公平锁。- 显示锁(ReetrantLock):
ReetrantLock
在java.util.concurrent.locks
包中,支持手动加解锁,公平锁(先来先得)以及条件变量(Condition)通知等待线程。
场景:适合需要更复杂锁控制,如可以中断的锁请求、公平锁、条件等待的场景,常见于生产者消费者模式等。- 读写锁(ReentrantReadWriteLock):读写锁区分读锁和写锁,多个线程可以同时持有读锁,但写锁是独占的。适用于读多写少的场景,提升并发性能。
场景:缓存读取、配置文件访问,读操作频繁且写操作较少的应用。- StampedLock:Java 8引入,比 ReentrantReadWriteLock更高效,支持乐观读锁,读操作时不加锁直接读,若读期间无写则数据有效。
场景:高并发读操作且对性能敏感的场景。- 自旋锁(基于 CAS,Atomic 类):自旋锁不会阻塞线程,而是不断尝试获取锁,适合临界区极短的场景,避免线程切换开销。
场景:短时间临界区,性能敏感的场合。- Semaphore(信号量):控制对某个资源的访问线程数量,而非互斥锁。
场景:连接池、限流场景。
7. 什么是反射?有哪些使用场景?
反射是 Java 提供的一种强大机制,允许程序在运行时动态地获取类的信息、调用方法、访问属性、创建对象等。通过反射,程序不需要在编译时就知道具体的类名、方法名或字段名,可以在运行时灵活处理未知类。
常用反射操作:
- 获取类的 class 对象(
Class.forName()、对象.getClass()
)- 动态创建实例(
clazz.newInstance() 或 Constructor.newInstance()
)- 获取方法/字段/构造器(
getDeclaredMethod() / getDeclaredField()
等)- 动态调用方法、访问/修改字段值
场景:
- 框架底层实现(Spring、MyBatis、Hibernate 等)。Spring 通过反射注入依赖(DI)或创建 Bean。MyBatis 通过反射读取实体类字段,动态生成 SQL。
- 动态加载类或调用方法(插件机制)。比如 Tomcat 加载 .class 文件处理请求,不提前写死实现类。
- 序列化/反序列化库(如 Jackson、Gson)。反射用来获取字段和构造器,把 JSON 转为 Java 对象。
- Junit 单元测试框架。测试框架用反射执行 @Test 注解的方法。
- 开发通用工具类、ORM 框架等。比如通用 BeanUtils.copyProperties() 使用反射复制对象字段。
- 访问私有成员(绕开访问权限)。比如通过反射修改 private 字段,调用 private 方法(不推荐但可以做到)。
8. 慢查询是如何调试解决的?
慢查询是指执行时间超过预期或设定阈值的 SQL 查询,它通常由于索引缺失、数据量大、SQL 设计不合理等原因造成。
- 确认慢查询来源:首先通过 MySQL 的慢查询日志或性能监控工具(如 performance_schema、APM 系统等)来定位具体的慢 SQL,确认哪些查询响应时间长、频率高,是优化重点。
- 分析执行计划:使用 EXPLAIN 分析慢查询的执行计划,查看是否使用了索引、是否发生了全表扫描、是否有 Using temporary、Using filesort 等性能问题,从而判断瓶颈所在。
- 优化查询语句:根据执行计划结果优化 SQL,例如添加合适的索引、优化 WHERE 条件、避免使用 SELECT *、重写嵌套或关联查询等,确保查询能命中索引并减少不必要的扫描。
- 优化数据库结构:如果是由于数据量大或设计不合理导致查询慢,可以考虑对表进行水平拆分、增加冗余字段、字段反范式设计等,优化存储结构以减少数据读取成本。
- 引入缓存机制:对于访问频繁但更新不频繁的数据,可以使用如 Redis 等缓存系统,避免重复从数据库中查询,提高整体响应速度。
9. MySQL的explain有什么作用?
EXPLAIN 是 MySQL 提供的查询执行计划分析工具,用于预估 SQL 在执行时的执行方式。通过 EXPLAIN 可以查看 MySQL 在执行 SELECT、UPDATE 或 DELETE 语句时,是否使用了索引、连接顺序、扫描方式、返回行数估计等信息,从而帮助我们识别慢查询并进行优化。
EXPLAIN 返回的一些核心字段及其含义:
字段名 | 作用说明 |
---|---|
id |
查询语句中每个 SELECT 的唯一标识,值越大优先级越高 |
select_type |
查询类型,如 SIMPLE、PRIMARY、SUBQUERY、DERIVED 等 |
table |
当前这一步操作的是哪张表或临时表 |
type |
连接类型(访问类型),越靠近 ALL 性能越差,最佳为 const 或 eq_ref |
possible_keys |
查询可能用到的索引 |
key |
实际使用的索引 |
key_len |
索引字段的长度 |
ref |
哪个字段与索引进行比较 |
rows |
MySQL 预估需要读取的行数 |
Extra |
额外信息,如 Using index (覆盖索引)、Using temporary (使用临时表)、Using filesort (使用文件排序)等,是优化关注重点 |