什麼是MQ,nginx面試題負載均衡

熬夜布禿頭啊 2021-09-20 01:56:29 阅读数:300

mq nginx 均衡

17
18 channel.queueDeclare(TASK_QUEUE_NAME, true, false,false,null);
19 System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
20
21 channel.basicQos(1);
22
23 DeliverCallback deliverCallback = (comsumerTag, delivery) ->{
24 String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
25
26 System.out.println(" [x] Received ‘" + message + "’“);
27
28 try {
29 doWork(message);
30 } finally {
31 System.out.println(”[x] Done");
32 channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
33 }
34 };
35 channel.basicConsume(TASK_QUEUE_NAME, false, deliverCallback, comsumerTag -> {});
36 }
37
38 private static void doWork(String task){
39 for (char ch : task.toCharArray()){
40 if(ch == ‘.’){
41 try {
42 Thread.sleep(1000);
43 } catch (InterruptedException e) {
44 Thread.currentThread().interrupt();
45 }
46 }
47 }
48 }
49 }


## 4.3 Publish/Subscribe(發布/訂閱)
官方描述:
RabbitMQ消息傳遞模型中的核心思想是生產者從不將任何消息直接發送到隊列。實際上,生產者經常甚至根本不知道是否將消息傳遞到任何隊列。相反,生產者只能將消息發送到交換機。交流是一件非常簡單的事情。一方面,它接收來自生產者的消息,另一方面,將它們推入隊列。交易所必須確切知道如何處理收到的消息。是否應將其附加到特定隊列?是否應該將其附加到許多隊列中?還是應該丟弃它。規則由交換類型定義 。
簡而言之:
相當於我們關注了一個微信公眾號,公眾號每次推文我們都能及時的收到。我們就相當於消費者,公眾號相當於消息中轉站,文章作者相當於生產者。
代碼示例:
生產者:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

1 public class EmitLog {
2
3 private static final String ExCHANGE_NAME = “logs”;
4
5 public static void main(String[] args) throws Exception{
6
7 ConnectionFactory factory = new ConnectionFactory();
8
9 // 設置IP
10 factory.setHost(“127.0.0.1”);
11
12 // 設置端口號
13 factory.setPort(5672);
14
15 try (Connection connection = factory.newConnection();
16 Channel channel = connection.createChannel()){
17 channel.exchangeDeclare(ExCHANGE_NAME, “fanout”);
18
19 String message = args.length < 1 ? “info: Hello World!” : String.join(" “, args);
20
21 channel.basicPublish(ExCHANGE_NAME, “”, null, message.getBytes(StandardCharsets.UTF_8));
22
23 System.out.println(” [x] Sent ‘" + message + "’");
24
25 }
26
27 }
28
29 }


消費者:

  • 1.
  • 2.
  • 3.

1 public class ReceiveLogs {
2
3 private static final String ExCHANGE_NAME = “logs”;
4
5 public static void main(String[] args) throws Exception{
6 ConnectionFactory factory = new ConnectionFactory();
7
8 // 設置IP
9 factory.setHost(“127.0.0.1”);
10
11 // 設置端口號
12 factory.setPort(5672);
13
14 Connection connection = factory.newConnection();
15 Channel channel = connection.createChannel();
16
17 channel.exchangeDeclare(ExCHANGE_NAME, “fanout”);
18 String queueName = channel.queueDeclare().getQueue();
19 channel.queueBind(queueName, ExCHANGE_NAME, “”);
20
21 System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
22
23 DeliverCallback deliverCallback = (sonsumerTag, delivery) -> {
24 String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
25 System.out.println(" [x] Received ‘" + message + "’");
26 };
27 channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {});
28 }
29 }


## 4.4 Routing(路由)
官方描述:
接上例,我們可能希望將日志消息寫入磁盤的程序僅接收嚴重錯誤,而不會在警告或信息日志消息上浪費磁盤空間。
簡而言之:
如果我們只想接收某些信息,比如日志級別有INFO、ERROR、DEBUG等,我們只願接收INFO日志。可以使用Routing進行過濾。
代碼示例:
生產者:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

1 public class EmitLogDirect {
2
3 private static final String EXCHANGE_NAME = “direct_logs”;
4
5 public static void main(String[] args) throws Exception{
6
7 ConnectionFactory factory = new ConnectionFactory();
8
9 // 設置IP
10 factory.setHost(“127.0.0.1”);
11
12 // 設置端口號
13 factory.setPort(5672);
14
15 try (Connection connection = factory.newConnection();
16 Channel channel = connection.createChannel()){
17 channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
18
19 String severity = getServerity(args);
20 String message = getMessage(args);
21
22 channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes(StandardCharsets.UTF_8));
23 System.out.println(" [x] Sent ‘" + severity + "’:‘" + message + "’");
24
25 }
26
27 }
28
29 private static String getServerity(String[] strings){
30 if (strings.length < 1){
31 return “info”;
32 }
33 return strings[0];
34
35 }
36
37 private static String getMessage(String[] strings){
38 if (strings.length < 2) {
39 return “Hello World!”;
40 }
41 return joinStrings(strings, " ", 1);
42 }
43
44 private static String joinStrings(String[] strings, String delimiter, int startIndex){
45 int length = strings.length;
46 if(length == 0){
47 return “”;
48 }
49 if(length <= startIndex){
50 return “”;
51 }
52 StringBuilder words = new StringBuilder(strings[startIndex]);
53 for (int i = startIndex + 1; i < length; i++){
54 words.append(delimiter).append(strings[i]);
55 }
56 return words.toString();
57
58 }
59 }


消費者:

  • 1.
  • 2.
  • 3.

1 public class ReceiveLogsDirect {
2
3 private static final String EXCHANGE_NAME = “direct_logs”;
4
5 public static void main(String[] args) throws Exception{
6
7 ConnectionFactory factory = new ConnectionFactory();
8
9 // 設置IP
10 factory.setHost(“127.0.0.1”);
11
12 // 設置端口號
13 factory.setPort(5672);
14
15 Connection connection = factory.newConnection();
16
17 Channel channel = connection.createChannel();
18
19 channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
20
21 String queueName = channel.queueDeclare().getQueue();
22
23 if(args.length < 1){
24 System.err.println(“Usage: ReceiveLogsDirect [info] [warning] [error]”);
25 System.exit(1);
26 }
27
28 for (String severity : args){
29 channel.queueBind(queueName, EXCHANGE_NAME, severity);
30 }
31 System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
32
33 DeliverCallback deliverCallback = (consumerTag, delivery)->{
34 String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
35 System.out.println(" [x] Received ‘" + delivery.getEnvelope().getRoutingKey() + "’:‘" + message + "’");
36 };
37
38 channel.basicConsume(queueName, true, deliverCallback, comsumerTag ->{});
39 }
40 }


## 4.5 Topics(主題)
官方描述:
發送到主題交換機的消息不能具有任意的 routing_key-它必須是單詞列錶,以點分隔。這些詞可以是任何東西,但通常它們指定與消息相關的某些功能。一些有效的路由關鍵示例:“ stock.usd.nyse ”,“ nyse.vmw ”,“ quick.orange.rabbit ”。路由關鍵字中可以包含任意多個單詞,最多255個字節。
綁定密鑰也必須采用相同的形式。主題交換背後的邏輯 類似於直接交換-用特定路由鍵發送的消息將傳遞到所有用匹配綁定鍵綁定的隊列。但是,綁定鍵有兩個重要的特殊情况:
* *(星)只能代替一個單詞。#(散列)可以代替零個或多個單詞。
簡而言之:
Topic會根據消息自身所攜帶的路由鍵(Routing Key)在所有的綁定關系中尋找,與消息相匹配的隊列推送該消息。
注意:
當在綁定中不使用特殊字符“ * ”(星號)和“ # ”(哈希)時,主題交換的行為就像直接的一樣。
代碼示例:
生產者:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

1 public class EmitLogTopic {
2
3 private static final String EXCHANGE_NAME = “topic_logs”;
4
5 public static void main(String[] args) throws Exception{
6
7 ConnectionFactory factory = new ConnectionFactory();
8 // 設置IP
9 factory.setHost(“127.0.0.1”);
10
11 // 設置端口號
12 factory.setPort(5672);
13
14 try(Connection connection = factory.newConnection();
15 Channel channel = connection.createChannel()){
16
17 channel.exchangeDeclare(EXCHANGE_NAME, “topic”);
18
19 String routingKey = getRouting(args);
20 String message = getMessage(args);
21
22 channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes(StandardCharsets.UTF_8));
23 System.out.println(" [x] Sent ‘" + routingKey + "’:‘" + message + "’");
24 }
25 }
26
27 private static String getRouting(String[] strings){
28 if (strings.length < 1){
29 return “anonymous.info”;
30 }
31 return strings[0];
32 }
33
34 private static String getMessage(String[] strings){
35 if (strings.length < 2){
36 return “hello world”;
37 }
38 return joinStrings(strings, " ", 1);
39 }
40
41 private static String joinStrings(String[] strings, String delimiter, int startIndex){
42 int length = strings.length;
43 if(length == 0){
44 return “”;
45 }
46 if(length < startIndex){
47 return “”;
48 }
49 StringBuilder words = new StringBuilder(strings[startIndex]);
50 for (int i = startIndex + 1; i < length; i++){
51 words.append(delimiter).append(strings[i]);
52 }
53 return words.toString();
54 }
55 }


消費者:

  • 1.
  • 2.
  • 3.

1 public class ReceiveLogTopic {
2
3 private static final String EXCHANGE_NAME = “topic_logs”;
4
5 public static void main(String[] args) throws Exception{
6
7 ConnectionFactory factory = new ConnectionFactory();
8 // 設置IP
9 factory.setHost(“127.0.0.1”);
10
11 // 設置端口號
12 factory.setPort(5672);
13
14 Connection connection = factory.newConnection();
15 Channel channel = connection.createChannel();
16
17 channel.exchangeDeclare(EXCHANGE_NAME, “topic”);
18
19 String queueName = channel.queueDeclare().getQueue();
20
21 if(args.length < 1){
22 System.err.println(“Usage: ReceiveLogsTopic [binding_key]…”);
23 System.exit(1);
24 }
25
26 for (String bindingKey : args){
27 channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
28 }
29
30 System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
31
32 DeliverCallback deliverCallback = (consumerTag, delivery) -> {
33 String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
34 System.out.println(" [x] Received ‘" + delivery.getEnvelope().getRoutingKey() + "’:‘" + message + "’");
35 };
36 channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {});
37 }
38 }


## 4.6 RPC(遠程過程調用)
官方描述:
盡管RPC是計算中非常普遍的模式,但它經常受到批評。當程序員不知道函數調用是本地的還是緩慢的RPC時,就會出現問題。這樣的混亂會導致系統變幻莫測,並給調試增加了不必要的複雜性。濫用RPC可能會導致無法維護的意大利面條代碼,而不是簡化軟件。
代碼示例:
生產者

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

1 public class RPCServer {
2
3 private static final String RPC_QUEUE_NAME = “rpc_queue”;
4
5 private static int fib(int n){
6 if(n == 0){
7 return 0;
8 }
9 if(n == 1){
10 return 1;
11 }
12 return fib(n - 1) + fib(n - 2);
13 }
14
15 public static void main(String[] args) throws Exception{
16
17 // 創建服務器的連接
18 ConnectionFactory factory = new ConnectionFactory();
19
20 // 設置IP
21 factory.setHost(“127.0.0.1”);
22
23 // 設置端口號
24 factory.setPort(5672);
25
26 try (Connection connection = factory.newConnection();
27 Channel channel = connection.createChannel()) {
28 channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);
29 channel.queuePurge(RPC_QUEUE_NAME);
30
31 channel.basicQos(1);
32
33 System.out.println(" [x] Awaiting RPC requests");
34
35 Object monitor = new Object();
36 DeliverCallback deliverCallback = (consumerTag, delivery) ->{
37 AMQP.BasicProperties replyProps = new AMQP.BasicProperties
38 .Builder()
39 .correlationId(delivery.getProperties().getCorrelationId())
40 .build();
41
42 String response = “”;
43
44 try{
45 String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
46 int n = Integer.parseInt(message);
47
48 System.out.println(" [.] fib(" + message + “)”);
49 response += fib(n);
50 }catch (RuntimeException e){
51 System.out.println(" [.] " + e.toString());
52 }finally {
53 channel.basicPublish(“”, delivery.getProperties().getReplyTo(), replyProps, response.getBytes(StandardCharsets.UTF_8));
54 channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
55
56 // RabbitMq consumer worker thread notifies the RPC server owner thread
57 // RabbitMq使用者工作線程通知RPC服務器所有者線程
58 synchronized (monitor){
59 monitor.notify();
60 }
61 }
62 };
63 channel.basicConsume(RPC_QUEUE_NAME, false, deliverCallback, (consumerTag -> {}));
64 // Wait and be prepared to consume the message from RPC client.
65 // 等待並准備使用來自RPC客戶端的消息。
66 while(true){
67 synchronized (monitor){
68 try {
69 monitor.wait();
70 }catch (InterruptedException e){

感受:

其實我投簡曆的時候,都不太敢投遞阿裏。因為在阿裏一面前已經過了字節的三次面試,投阿裏的簡曆一直沒被撈,所以以為簡曆就掛了。

特別感謝一面的面試官撈了我,給了我機會,同時也認可我的努力和態度。對比我的面經和其他大佬的面經,自己真的是運氣好。別人8成實力,我可能8成運氣。所以對我而言,我要繼續加倍努力,彌補自己技術上的不足,以及與科班大佬們基礎上的差距。希望自己能繼續保持學習的熱情,繼續努力走下去。

也祝願各比特同學,都能找到自己心動的offer。

分享我在這次面試前所做的准備(刷題複習資料以及一些大佬們的學習筆記和學習路線),都已經整理成了電子文檔

 CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】

什麼是MQ,nginx面試題負載均衡_後端

版权声明:本文为[熬夜布禿頭啊]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210920015628873s.html