4.7. 中间件¶
4.7.1. Web Server¶
Nginx¶
-
Nginx 通过异步非阻塞的事件处理机制实现高并发。Apache 每个请求独占一个线程,非常消耗系统资源。
事件驱动适合于IO密集型服务(Nginx),多进程或线程适合于CPU密集型服务(Apache),所以Nginx适合做反向代理,而非web服务器使用。
-
nginx只适合静态和反向代理,不适合处理动态请求。
OpenResty¶
-
通过 Lua 模块可以在Nginx上进行开发。
Tengine¶
Apache Httpd¶
Tomcat¶
架构原理¶
《JBoss vs. Tomcat: Choosing A Java Application Server》
Tomcat 是轻量级的 Serverlet 容器,没有实现全部 JEE 特性(比如持久化和事务处理),但可以通过其他组件代替,比如Spring。
Jboss 实现全部了JEE特性,软件开源免费、文档收费。
调优方案¶
-
启动NIO模式(或者APR);调整线程池;禁用AJP连接器(Nginx+tomcat的架构,不需要AJP);
-
AJP 协议(8009端口)用于降低和前端Server(如Apache,而且需要支持AJP协议)的连接数(前端),通过长连接提高性能。
并发高时,AJP协议优于HTTP协议。
Jetty¶
-
架构比较:Jetty的架构比Tomcat的更为简单。
性能比较:Jetty和Tomcat性能方面差异不大,Jetty默认采用NIO结束在处理I/O请求上更占优势,Tomcat默认采用BIO处理I/O请求,Tomcat适合处理少数非常繁忙的链接,处理静态资源时性能较差。
其他方面:Jetty的应用更加快速,修改简单,对新的Servlet规范的支持较好;Tomcat 对JEE和Servlet 支持更加全面。
4.7.2. 缓存¶
本地缓存¶
-
堆内、堆外、磁盘三级缓存。
可按照缓存空间容量进行设置。
按照时间、次数等过期策略。
-
简单轻量、无堆外、磁盘缓存。
4.7.3. 客户端缓存¶
-
主要是利用 Cache-Control 参数。
4.7.4. 服务端缓存¶
Web缓存¶
Memcached¶
-
采用多路复用技术提高并发性。
slab分配算法: memcached给Slab分配内存空间,默认是1MB。分配给Slab之后 把slab的切分成大小相同的chunk,Chunk是用于缓存记录的内存空间,Chunk 的大小默认按照1.25倍的速度递增。好处是不会频繁申请内存,提高IO效率,坏处是会有一定的内存浪费。
《memcache 中 add 、 set 、replace 的区别》
区别在于当key存在还是不存在时,返回值是true和false的。
Redis¶
-
使用 ziplist 存储链表,ziplist是一种压缩链表,它的好处是更能节省内存空间,因为它所存储的内容都是在连续的内存区域当中的。
使用 skiplist(跳跃表)来存储有序集合对象、查找上先从高Level查起、时间复杂度和红黑树相当,实现容易,无锁、并发性好。
-
RDB方式:定期备份快照,常用于灾难恢复。优点:通过fork出的进程进行备份,不影响主进程、RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。缺点:会丢数据。
AOF方式:保存操作日志方式。优点:恢复时数据丢失少,缺点:文件大,回复慢。
也可以两者结合使用。
架构¶
回收策略¶
Tair¶
特点:可以配置备份节点数目,通过异步同步到备份节点
一致性Hash算法。
架构:和Hadoop 的设计思想类似,有Configserver,DataServer,Configserver 通过心跳来检测,Configserver也有主备关系。
几种存储引擎:
MDB,完全内存性,可以用来存储Session等数据。
Rdb(类似于Redis),轻量化,去除了aof之类的操作,支持Restfull操作
LDB(LevelDB存储引擎),持久化存储,LDB 作为rdb的持久化,google实现,比较高效,理论基础是LSM(Log-Structured-Merge Tree)算法,现在内存中修改数据,达到一定量时(和内存汇总的旧数据一同写入磁盘)再写入磁盘,存储更加高效,县比喻Hash算法。
Tair采用共享内存来存储数据,如果服务挂掉(非服务器),重启服务之后,数据亦然还在。
4.7.5. 消息队列¶
《消息队列-推/拉模式学习 & ActiveMQ及JMS学习》
RabbitMQ 消费者默认是推模式(也支持拉模式)。
Kafka 默认是拉模式。
Push方式:优点是可以尽可能快地将消息发送给消费者,缺点是如果消费者处理能力跟不上,消费者的缓冲区可能会溢出。
Pull方式:优点是消费端可以按处理能力进行拉去,缺点是会增加消息延迟。
消息总线¶
消息总线相当于在消息队列之上做了一层封装,统一入口,统一管控、简化接入成本。
消息的顺序¶
RabbitMQ¶
支持事务,推拉模式都是支持、适合需要可靠性消息传输的场景。
RocketMQ¶
Java实现,推拉模式都是支持,吞吐量逊于Kafka。可以保证消息顺序。
ActiveMQ¶
纯Java实现,兼容JMS,可以内嵌于Java应用中。
Kafka¶
高吞吐量、采用拉模式。适合高IO场景,比如日志同步。
Redis 消息推送¶
生产者、消费者模式完全是客户端行为,list 和 拉模式实现,阻塞等待采用 blpop 指令。
ZeroMQ¶
TODO
4.7.6. 定时调度¶
单机定时调度¶
-
fork 进程 + sleep 轮询
-
定时调度在 QuartzSchedulerThread 代码中,while()无限循环,每次循环取出时间将到的trigger,触发对应的job,直到调度器线程被关闭。
分布式定时调度¶
-
opencron、LTS、XXL-JOB、Elastic-Job、Uncode-Schedule、Antares
-
Quartz集群中,独立的Quartz节点并不与另一其的节点或是管理节点通信,而是通过相同的数据库表来感知到另一Quartz应用的
4.7.7. RPC¶
-
核心角色:Server: 暴露服务的服务提供方、Client: 调用远程服务的服务消费方、Registry: 服务注册与发现的注册中心。
Dubbo¶
** SPI ** TODO
Thrift¶
-
支持多语言,通过中间语言定义接口。
gRPC¶
服务端可以认证加密,在外网环境下,可以保证数据安全。
4.7.8. 数据库中间件¶
4.7.9. 日志系统¶
日志搜集¶
4.7.10. 配置中心¶
-
Spring Boot 和 Spring Cloud
支持推、拉模式更新配置
支持多种语言
servlet 3.0 异步特性可用于配置中心的客户端
4.7.11. API 网关¶
主要职责:请求转发、安全认证、协议转换、容灾。