第八篇 项目优化篇 RabbitMQ + Nginx + ES + Dubbo + Zookeeper

1、消息队列的作用与使用场景?

消息队列在实际应用中常用的使用场景。异步处理,应用解耦,流量削锋消息通讯四个场景

2.1异步处理

场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式

(1)串行方式:

(2)并行方式:

假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。

因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)

小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?

引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:

按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍

2.2应用解耦

场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图

传统模式的缺点:

假如库存系统无法访问,则订单减库存将失败,从而导致订单失败

订单系统与库存系统耦合

如何解决以上问题呢?引入应用消息队列后的方案,如下图:

 

订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功

库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作

假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦

2.3流量削锋

流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛

应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。

可以控制活动的人数

可以缓解短时间内高流量压垮应用

用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面

秒杀业务根据消息队列中的请求信息,再做后续处理

2.4日志处理

日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。

日志采集客户端,负责日志数据采集,定时写受写入Kafka队列

Kafka消息队列,负责日志数据的接收,存储和转发

日志处理应用:订阅并消费kafka队列中的日志数据

以下是新浪kafka日志处理应用案例:点击查看

(1)Kafka:接收用户日志的消息队列

(2)Logstash:做日志解析,统一成JSON输出给Elasticsearch

(3)Elasticsearch:实时日志分析服务的核心技术,一个schemaless,实时的数据存储服务,通过index组织数据,兼具强大的搜索和统计功能

(4)Kibana:基于Elasticsearch的数据可视化组件,超强的数据可视化能力是众多公司选择ELK stack的重要原因

2.5消息通讯

消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等

点对点通讯:

客户端A和客户端B使用同一队列,进行消息通讯。

聊天室通讯:

客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。

以上实际是消息队列的两种消息模式,点对点或发布订阅模式。模型为示意图,供参考。

2、RabbitMQ如何保证消息的顺序性?

消息队列中的若干消息如果是对同一个数据进行操作,这些操作具有前后的关系,必须要按前后的顺序执行,否则就会造成数据异常。举例:

比如通过mysql binlog进行两个数据库的数据同步,由于对数据库的数据操作是具有顺序性的,如果操作顺序搞反,就会造成不可估量的错误。比如数据库对一条数据依次进行了 插入->更新->删除操作,这个顺序必须是这样,如果在同步过程中,消息的顺序变成了 删除->插入->更新,那么原本应该被删除的数据,就没有被删除,造成数据的不一致问题。

举例场景:

RabbitMQ:①一个queue,有多个consumer去消费,这样就会造成顺序的错误,consumer从MQ里面读取数据是有序的,但是每个consumer的执行时间是不固定的,无法保证先读到消息的consumer一定先完成操作,这样就会出现消息并没有按照顺序执行,造成数据顺序错误。

②一个queue对应一个consumer,但是consumer里面进行了多线程消费,这样也会造成消息消费顺序错误。

解决方案:

①拆分多个queue,每个queue一个consumer,就是多一些queue而已,确实是麻烦点;这样也会造成吞吐量下降,可以在消费者内部采用多线程的方式取消费。

一个queue对应一个consumer

②或者就一个queue但是对应一个consumer,然后这个consumer内部用内存队列做排队,然后分发给底层不同的worker来处理

一个queue对应一个consumer,采用多线程

3、如何使用RabbitMQ解决分布式事务?

分布式事务:不同的服务操作不同的数据源(库或表),保证数据一致性的问题。

解决:采用RabbitMQ消息最终一致性的解决方案,解决分布式事务问题。

分布式事务场景:

1、电商项目中的商品库和ES库数据同步问题。

           2、电商项目中:支付----à订单---à库存,一系列操作,进行状态更改等。

在互联网应用中,基本都会有用户注册的功能。在注册的同时,我们会做出如下操作:

收集用户录入信息,保存到数据库向用户的手机或邮箱发送验证码等等…

如果是传统的集中式架构,实现这个功能非常简单:开启一个本地事务,往本地数据库中插入一条用户数据,发送验证码,提交事物。

但是在分布式架构中,用户和发送验证码是两个独立的服务,它们都有各自的数据库,那么就不能通过本地事物保证操作的原子性。这时我们就需要用到 RabbitMQ(消息队列)来为我们实现这个需求。

在用户进行注册操作的时候,我们为该操作创建一条消息,当用户信息保存成功时,把这条消息发送到消息队列。验证码系统会监听消息,一旦接受到消息,就会给该用户发送验证码。

4、RabbitMQ如何确保消息可靠性?

消息可靠性一般来说由3方面来保证:

1) 生产者

    RabbitMQ提供transaction事务和confirm模式来确保生产者不丢消息;

    Transaction事务机制就是说:发送消息前,开启事务(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事务就会回滚                                       (channel.txRollback()),如果发送成功则提交事务(channel.txCommit()),然而,这种方式有个缺点:吞吐量下降。

    confirm模式用的居多:一旦channel进入confirm模式,所有在该信道上发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后;

    rabbitMQ就会发送一个ACK给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了;

    如果rabbitMQ没能处理该消息,则会发送一个Nack消息给你,可以进行重试操作。

2) 消息队列本身

       可以进行消息持久化, 即使rabbitMQ挂了,重启后也能恢复数据

       如果要进行消息持久化,那么需要对以下3种实体均配置持久化

       a) Exchange

       声明exchange时设置持久化(durable = true)并且不自动删除(autoDelete = false)

    b) Queue

    声明queue时设置持久化(durable = true)并且不自动删除(autoDelete = false)

    c) message

    发送消息时通过设置deliveryMode=2持久化消息

3) 消费者

    消费者丢数据一般是因为采用了自动确认消息模式,消费者在收到消息之后,处理消息之前,会自动回复RabbitMQ已收到消息;如果这时处理消息失败,就会丢失该消息;改为手动确认消息即可!手动确认模式下消费失败时,不将其重新放入队列(确认重试也不会成功的情形),打印错误信息后,通知相关人员,人工介入处理。

5、如何防止RabbitMQ消息重复消费?

保证消息幂等性。幂等性概念:一个请求,不管重复来多少次,结果是不会改变的。

RabbitMQ、RocketMQ、Kafka等任何队列不保证消息不重复,如果业务需要消息不重复消费,则需要消费端处理业务消息要保持幂等性

方式一:Redis的setNX() , 做消息id去重 java版本目前不支持设置过期时间

  //Redis中操作,判断是否已经操作过 TODO

  boolean flag =  jedis.setNX(key);

  if(flag){

    //消费

  }else{

    //忽略,重复消费

  }  

方式二:redis的 Incr 原子操作:key自增,大于0 返回值大于0则说明消费过,(key可以是消息的md5取值, 或者如果消息id设计合理直接用id做key)

  int num =  jedis.incr(key);

  if(num == 1){

      //消费

  }else{

      //忽略,重复消费

  }

方式三:数据库去重表

       设计一个去重表,某个字段使用Message的key做唯一索引,因为存在唯一索引,所以重复消费会失败

        CREATE TABLE `message_record` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `key` varchar(128) DEFAULT NULL, `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key` (`key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

6、如何解决消息队列的延时以及过期失效问题?消息队列满了之后该如何处理?有几百万的消息持续积压几小时,说说如何解决?

方案分析

该问题,其本质针对的场景,都是说,可能你的消费端出了问题,不消费了,或者消费的极其极其慢。另外还有可能你的消息队列集群的磁盘都快写满了,都没人消费,这个时候怎么办?或者是积压了几个小时,你这个时候怎么办?或者是你积压的时间太长了,导致比如rabbitmq设置了消息过期时间后就没了怎么办?

所以这种问题线上常见的,一般不出,一出就是大问题,一般常见于,举个例子,消费端每次消费之后要写mysql,结果mysql挂了,消费端挂掉了。导致消费速度极其慢。

分析1+话术

这个是我们真实遇到过的一个场景,确实是线上故障了,这个时候要不然就是修复consumer的问题,让他恢复消费速度,然后傻傻的等待几个小时消费完毕。(可行,但是不建议 在面试的时候说)

一个消费者一秒是1000条,一秒3个消费者是3000条,一分钟是18万条,1000多万条

所以如果你积压了几百万到上千万的数据,即使消费者恢复了,也需要大概1小时的时间才能恢复过来

一般这个时候,只能操作临时紧急扩容了,具体操作步骤和思路如下:

1)先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉

2)新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量

3)然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue

4)接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据

5)这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据

6)等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息

分析2+话术

rabbitmq是可以设置过期时间的,就是TTL,如果消息在queue中积压超过一定的时间就会被rabbitmq给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在mq里,而是大量的数据会直接搞丢。

这个情况下,就不是说要增加consumer消费积压的消息,因为实际上没啥积压,而是丢了大量的消息。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上12点以后,用户都睡觉了。

这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入mq里面去,把白天丢的数据给他补回来。也只能是这样了。

假设1万个订单积压在mq里面,没有处理,其中1000个订单都丢了,你只能手动写程序把那1000个订单给查出来,手动发到mq里去再补一次

分析3+话术

如果走的方式是消息积压在mq里,那么如果你很长时间都没处理掉,此时导致mq都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晚上再补数据吧。

7、如果让你写一个消息队列,该如何进行架构设计?说一下思路(上海)

面试官心理分析

(1)你有没有对某一个消息队列做过较为深入的原理的了解,或者从整体了解把握住一个mq的架构原理

(2)看看你的设计能力,给你一个常见的系统,就是消息队列系统,看看你能不能从全局把握一下整体架构设计,给出一些关键点出来

类似问题

如果让你来设计一个spring框架你会怎么做?如果让你来设计一个dubbo框架你会怎么做?如果让你来设计一个mybatis框架你会怎么做?

回答思路

(1)首先这个mq得支持可伸缩性吧,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么搞?设计个分布式的系统

(2)其次你得考虑一下这个mq的数据要不要落地磁盘吧?那肯定要了,落磁盘,才能保证别进程挂了数据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的。

(3)其次你考虑一下你的mq的可用性啊?

(4)能不能支持数据0丢失啊?

面试官问你这个问题,其实是个开放题,他就是看看你有没有从架构角度整体构思和设计的思维以及能力。确实这个问题可以刷掉一大批人,因为大部分人平时不思考这些东西。

8、什么是ElasticSearch? 怎么解决中文分词?(北京)

Elasticsearch是一个基于Lucene的搜索引擎。它提供了具有HTTP Web界面和无架构JSON文档的分布式,多租户能力的全文搜索引擎。Elasticsearch是用Java开发的,根据Apache许可条款作为开源发布。

采用IK中文分词器插件进行中文分词处理。

9、Elasticsearch中的倒排索引是什么?(北京)

正排索引:

在说倒排索引之前我们先说说什么是正排索引。正排索引也称为"前向索引",它是创建倒排索引的基础。

这种组织方法在建立索引的时候结构比较简单,建立比较方便且易于维护;因为索引是基于文档建立的,若是有新的文档加入,直接为该文档建立一个新的索引块,挂接在原来索引文件的后面。若是有文档删除,则直接找到该文档号文档对应的索引信息,将其直接删除。

他适合根据文档ID来查询对应的内容。但是在查询一个keyword在哪些文档里包含的时候需对所有的文档进行扫描以确保没有遗漏,这样就使得检索时间大大延长,检索效率低下。

比如有几个文档及里面的内容,他正排索引构建的结果如下图:

优点:工作原理非常的简单。

缺点:检索效率太低,只能在一起简单的场景下使用。

倒排索引:

根据字面意思可以知道他和正序索引是反的。在搜索引擎中每个文件都对应一个文件ID,文件内容被表示为一系列关键词的集合(文档要除去一些无用的词,比如’的’这些,剩下的词就是关键词,每个关键词都有自己的ID)。例如“文档1”经过分词,提取了3个关键词,每个关键词都会记录它所在在文档中的出现频率及出现位置。

那么上面的文档及内容构建的倒排索引结果会如下图(注:这个图里没有记录展示该词在出现在哪个文档的具体位置):

如何来查询呢?

比如我们要查询‘搜索引擎’这个关键词在哪些文档中出现过。首先我们通过倒排索引可以查询到该关键词出现的文档位置是在1和3中;然后再通过正排索引查询到文档1和3的内容并返回结果。

10、Dubbo执行流程是什么样的?各个组件作用(北京)

它的架构主要有五个角色/核心组件,分为是Container(容器)、Provider(服务的提供方)、Registry(注册中心)、Consumer(服务的消费方)、Monitor(监控中心)。            

容器主要负责启动、加载、运行服务提供者;

同时服务提供者在启动时,向注册中心注册自己提供的服务;

消费者向注册中心订阅自己的服务;

注册中心返回服务提供者列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者;

对于服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另外一台调用;

服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心;

注册中心:

  1. 注册中心只负责地址的注册和查找,相当于我们的目录服务,只有在容器启动时,服务提供者和调用者与注册中心交互,整个过程,注册中心不参与数据传输,不转发请求,压力较小 (“两不一小”);
  2. 注册中心宕机问题:(Dubbo挂了怎么办?)

    注册中心会部署集群,

如果集群中的任意一台宕机之后,将自动切换到另外一台,不会影响已运行的提供者和消费者;

如果集群中所有注册中心全部宕机之后,服务提供者和服务消费者仍能通过本地缓存通讯;注册中心仍能通过缓存提供服务列表查询,但不能注册新服务;

监控中心:

  1. 监控中心负责统计各服务调用次数、调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
  2. 监控中心宕机不影响使用,只是丢失部分的采样数据;
  3. dubbo-admin可以通过监控中心的可视化界面,进行禁止服务和截止消费者(大量恶意访问的ip);

11、ZooKeeper是什么?(北京)

ZooKeeper是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。

Zookeeper保证了如下分布式一致性特性:

  1. 顺序一致性
  2. 原子性
  3. 单一视图
  4. 可靠性
  5. 实时性(最终一致性)

客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的zookeeper机器来处理。对于写请求,这些请求会同时发给其他zookeeper机器并且达成一致后,请求才会返回成功。因此,随着zookeeper的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。

有序性是zookeeper中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个zookeeper最新的zxid。

12、Zookeeper Watcher 机制 -- 数据变更通知(北京)

Zookeeper允许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据Watcher通知状态和事件类型做出业务上的改变。

工作机制:

  1. 客户端注册watcher
  2. 服务端处理watcher
  3. 客户端回调watcher

Watcher特性总结:

(1)一次性

无论是服务端还是客户端,一旦一个Watcher被触发,Zookeeper都会将其从相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。

(2)客户端串行执行

客户端Watcher回调的过程是一个串行同步的过程。

(3)轻量

Watcher通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。

客户端向服务端注册Watcher的时候,并不会把客户端真实的Watcher对象实体传递到服务端,仅仅是在客户端请求中使用boolean类型属性进行了标记。

watcher event异步发送watcher的通知事件从server发送到client是异步的,这就存在一个问题,不同的客户端和服务器之间通过socket进行通信,由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于Zookeeper本身提供了ordering guarantee,即客户端监听事件后,才会感知它所监视znode发生了变化。所以我们使用Zookeeper不能期望能够监控到节点每次的变化。Zookeeper只能保证最终的一致性,而无法保证强一致性。

注册watcher getData、exists、getChildren

触发watcher create、delete、setData

当一个客户端连接到一个新的服务器上时,watch将会被以任意会话事件触发。当与一个服务器失去连接的时候,是无法接收到watch的。而当client重新连接时,如果需要的话,所有先前注册过的watch,都会被重新注册。通常这是完全透明的。只有在一个特殊情况下,watch可能会丢失:对于一个未创建的znode的exist watch,如果在客户端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个watch事件可能会被丢失。

13、ZooKeeper分布式锁的实现原理(北京)

使用zookeeper创建临时序列节点来实现分布式锁,适用于顺序执行的程序,大体思路就是创建临时序列节点,找出最小的序列节点,获取分布式锁,程序执行完成之后此序列节点消失,通过watch来监控节点的变化,从剩下的节点的找到最小的序列节点,获取分布式锁,执行相应处理。

14、Nginx原理(北京)

Nginx内部进程模型:

1.nginx启动后,会有一个master进程和多个worker进程,master进程主要用来管理worker进程,包括:接受信号,将信号分发给worker进程,监听worker进程工作状态,当worker进程退出时(非正常),启动新的worker进程。基本的网络事件会交给worker进程处理。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的 。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。 worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的 

2.master接收到重新加载的信号会怎么处理(./nginx -s reload)?master会重新加载配置文件,然后启动新的进程,使用的新的worker进程来接受请求,并告诉老的worker进程他们可以退休了,老的worker进程将不会接受新的,老的worker进程处理完手中正在处理的请求就会退出。

3.worker进程是如何处理用户的请求呢?首先master会根据配置文件生成一个监听相应端口的socket,然后再faster出多个worker进程,这样每个worker就可以接受从socket过来的消息(其实这个时候应该是每一个worker都有一个socket,只是这些socket监听的地址是一样的)。当一个连接过来的时候,每一个worker都能接收到通知,但是只有一个worker能和这个连接建立关系,其他的worker都会连接失败,这就是所谓的惊群现在,为了解决这个问题,nginx提供一个共享锁accept_mutex,有了这个共享锁后,就会只有一个worker去接收这个连接。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。

master-workers的机制的好处

首先,对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。

其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快启动新的worker进程。

当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低了风险。

需要设置多少个worker

Nginx 同redis类似都采用了io多路复用机制,每个worker都是一个独立的进程,但每个进程里只有一个主线程,通过异步非阻塞的方式来处理请求, 即使是千上万个请求也不在话下。每个worker的线程可以把一个cpu的性能发挥到极致。

所以worker数和服务器的cpu数相等是最为适宜的。设少了会浪费cpu,设多了会造成cpu频繁切换上下文带来的损耗。

#设置worker数量

worker_processes 4

#work绑定cpu(4 work绑定4cpu)。

worker_cpu_affinity 0001 0010 0100 1000

#work绑定cpu (4 work绑定8cpu中的4个) 。

worker_cpu_affinity 00000001 00000010 00000100 00001000  00010000  00100000 01000000  10000000

#连接数

worker_connections 1024

这个值是表示每个worker进程所能建立连接的最大值,所以,一个nginx能建立的最大连接数,应该是worker_connections * worker_processes。当然,这里说的是最大连接数,对于HTTP请求本地资源来说,能够支持的最大并发数量是worker_connections * worker_processes,如果是支持http1.1的浏览器每次访问要占两个连接,所以普通的静态访问最大并发数是: worker_connections * worker_processes /2,而如果是HTTP作为反向代理来说,最大并发数量应该是worker_connections * worker_processes/4。

15、Nginx作用以及常见配置(北京)

作用:反向代理、负载均衡、动静分离(静态资源服务器,可以进行图片等资源管理)

具体配置实现:

反向代理:

在 nginx.conf 配置文件中增加如下配置

负载均衡:

常见策略

权重:weight代表权,重默认为1,权重越高被分配的客户端越多

指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 例如:

upstream server_pool{  

server 192.168.5.21 weight=1;   

server 192.168.5.22 weight=2;

server 192.168.5.23 weight=3;  

}

ip_hash每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 例如:

upstream server_pool{  

ip_hash;   

server 192.168.5.21:80;   

server 192.168.5.22:80;   

}

fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。

upstream server_pool{  

server 192.168.5.21:80;   

server 192.168.5.22:80;   

fair;   

}

轮询(默认)

 

静态资源(动静分离):

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
软件工程常用文档模板及示例:项目计划、需求分析、概要设计、详细设计、用户操作手册、测试计划、测试分析报告、开发进度报告、项目开发总结报告、软件维护手册等。 一、计划阶段 01 项目信息表 项目信息表 - 模板 项目信息表 - 示例 02 项目实施方案-PPT版 项目实施方案 - 模板1 项目实施方案 - 模板2 项目实施方案 - 示例 03 项目实施方案-Word版 项目实施方案 - 模板 项目实施方案 - 示例 04 项目实施进度计划 项目实施进度计划- 模板 项目实施进度计划- 示例 05 项目实施进度简表 项目实施进度简表 - 模板 项目实施进度简表 - 示例 二、需求阶段 需求规格说明书 - 模板 需求规格说明书 - 示例 三、设计阶段 功能设计说明书 - 模板 功能设计说明书 - 示例 数据库设计说明书 - 模板 数据库设计说明书 - 示例 四、开发阶段 系统提测申请单 - 模板 系统提测申请单 - 示例 五、测试阶段 01 测试用例 测试用例表 - 模板 测试用例表 - 示例 02 测试报告 系统测试报告 - 模板 系统测试报告 - 示例 六、验收阶段 01 系统竣工报告 系统竣工报告 - 模板 系统竣工报告 - 示例 02 安装维护手册 安装维护手册 - 模板 安装维护手册 - 示例 03 培训文档 培训文档 - 模板 培训文档 - 示例 04 使用手册 使用手册 - 模板 使用手册 - 示例 七、其他模板 工时统计表 - 模板 工时统计表 - 示例 会议纪要 - 模板 会议纪要 - 示例 项目进度简报 - 模板 项目进度确认单 - 模板 项目进度确认单 - 示例 项目月报 - 模板 项目月报 - 示例 项目周报 - 模板 项目周报 - 示例
Spring Boot是一个非常流行的Java Web框架,它简化了Java应用程序的开发和部署过程。 RabbitMQ是一个开源的消息代理,它支持多种协议,包括AMQP、STOMP和MQTT等。TLS协议则是一种加密传输协议,它可以保证数据在传输过程中的安全性。 在Spring Boot应用程序中使用RabbitMQ需要引入相应的依赖,可以使用Maven或Gradle来进行管理。同时,为了保证消息的安全传输,我们可以使用TLS协议对消息进行加密传输。 以下是使用Spring Boot和RabbitMQ进行消息传输并加密的简单示例: 1. 引入依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-rsa</artifactId> </dependency> ``` 2. 配置RabbitMQ和TLS 在application.properties文件中添加以下配置: ```properties spring.rabbitmq.host=localhost spring.rabbitmq.port=5671 spring.rabbitmq.username=user spring.rabbitmq.password=password spring.rabbitmq.ssl.enabled=true spring.rabbitmq.ssl.key-store=file:/path/to/keystore spring.rabbitmq.ssl.key-store-password=changeit spring.rabbitmq.ssl.trust-store=file:/path/to/truststore spring.rabbitmq.ssl.trust-store-password=changeit ``` 其中,key-store和trust-store分别为用于TLS加密的密钥库和信任库文件路径,需要根据实际情况进行配置。 3. 发送和接收消息 在Spring Boot应用程序中使用RabbitTemplate来发送和接收消息,示例代码如下: ```java @Service public class RabbitMQService { @Autowired private RabbitTemplate rabbitTemplate; public void send(String message) { rabbitTemplate.convertAndSend("exchange", "routingKey", message); } @RabbitListener(queues = "queue") public void receive(String message) { System.out.println("Received message: " + message); } } ``` 其中,send方法用于发送消息,receive方法用于接收消息。在这个例子中,我们将消息发送到名为exchange的交换机,使用名为routingKey的路由键进行路由,然后将消息发送到名为queue的队列中进行消费。 以上就是在Spring Boot应用程序中使用RabbitMQ和TLS进行消息传输的简单示例。需要注意的是,这只是一个基本的示例,实际应用中还需要进行更多的配置和处理,以确保消息传输的安全和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值