Q& a Classroom Collection of Basic and Advanced Chapter Thinking Questions and Answers

Q&A Classroom - Collection of basic and advanced chapter thinking questions and answers #

数组是一种数据结构,用于存储一系列相同类型的元素。它可以按顺序访问和操作其中的元素。每个元素可以通过索引来访问,索引从0开始,依次递增。数组的大小是固定的,在创建时需要指定元素的个数,且不能随意增加或减少。

Q2: 什么是函数? #

函数是一个可执行的代码块,可以通过函数名来调用执行。它可以接受输入参数,处理并返回结果。函数可以重复使用,有助于提高代码的可读性和复用性。

Q3: 什么是循环? #

循环是一种控制结构,用于重复执行一段代码。它可以根据指定的条件重复执行代码块,直到条件不再满足。常见的循环有while循环和for循环。循环使得我们可以简化重复的操作,提高代码的效率。

Q4: 什么是条件语句? #

条件语句是一种控制结构,用于根据给定条件执行不同的代码块。它可以根据条件的结果选择性地执行某一段代码。常见的条件语句有if语句和else语句。条件语句使得程序可以根据不同的情况执行不同的逻辑,增加了程序的灵活性。

Q5: 怎样定义一个变量? #

在大多数编程语言中,变量由一个标识符和值组成。标识符是变量的名称,用于在程序中引用该变量。值是赋给变量的数据,可以是数字、字符串、布尔值等。变量的定义通常需要指定数据类型和初始值(可选),例如:int age = 25;

Q6: 如何输出内容到控制台? #

在大多数编程语言中,可以使用特定的语句将内容输出到控制台。例如,在Java中,可以使用System.out.println()语句输出内容。在Python中,可以使用print()函数输出内容。输出的内容可以是字符串、变量值或表达式结果。

Q7: 什么是字符串? #

字符串是一串字符的序列,用于表示文本。它由0个或多个字符组成,字符可以是字母、数字、标点符号等。字符串可以用单引号或双引号括起来,例如:"Hello, world!"。字符串的长度可以通过length()函数或属性来获取。

Q8: 怎样比较两个值是否相等? #

在大多数编程语言中,可以使用特定的运算符来比较两个值是否相等。例如,在Java中,可以使用==运算符来比较两个值是否相等。在Python中,可以使用==运算符进行相等性比较。需要注意的是,字符串的比较一般使用equals()方法或运算符==

Q9: 如何使用数组? #

可以通过以下步骤使用数组:

  1. 声明数组:指定数组的类型和名称,例如int[] numbers;
  2. 创建数组:使用关键字new创建数组对象,例如numbers = new int[5];,表示创建一个包含5个整数的数组。
  3. 初始化数组:可以在创建数组时为元素赋初值,或在后续操作中逐个赋值。
  4. 访问数组元素:通过索引访问数组中的元素,索引从0开始。
  5. 操作数组元素:可以对数组元素进行赋值、修改和运算等操作。

Q10: 怎样定义一个函数? #

在大多数编程语言中,可以使用特定的语法来定义函数。函数定义通常包括函数名、参数列表和函数体。例如,在Python中可以这样定义一个函数:

def greet(name):
    print("Hello, " + name)

函数名用于调用函数,参数列表用于接收输入参数,函数体包含实现函数功能的代码。

希望以上回答能对你有所帮助。如果你还有其他疑问,欢迎继续提问。

Lecture 2 #

Thought Question: How do we associate requests with responses in RPC?

First of all, we need to understand why we need to associate requests with responses. This is because in the RPC calling process, the caller sends request messages to the server, and then it receives response messages from the server. However, these two operations are not performed synchronously. In a high-concurrency scenario, the caller may send multiple messages to the server at a certain moment before receiving various response messages from the server one by one. In this case, the caller needs a means to distinguish which response message corresponds to which previous request message. Therefore, we say that RPC needs to associate requests with responses when sending messages.

Solving this problem is not difficult. After receiving a response message, the caller only needs to read an identifier from the response message to tell the caller which request message the response message belongs to. In this lecture, you will find that in the private protocols we design, there is always a message ID, which serves the purpose of associating requests with responses. The caller generates a unique message ID for each message it sends, and if it receives a response message with the same message ID from the server, the caller can consider that the response message belongs to the previous request message.

Chapter 5 #

Reflection question: If we don’t have dynamic proxies to help us intercept method calls, how can users make RPC calls?

We can refer to the gRPC framework for this question. The gRPC framework does not use dynamic proxies. Instead, it generates service stubs through code generation. Of course, these service stubs play the same role as dynamic proxies in RPC frameworks.

The main reason why gRPC framework uses code-generated service stubs instead of dynamic proxies is to support clients in multiple languages. There are some languages that do not support dynamic proxies, such as C++ and Go. However, the drawbacks are also obvious. If you have used gRPC, you would find that generating service stubs through code generation is more cumbersome compared to using dynamic proxies. It is not as convenient and transparent as using dynamic proxies.

Lecture 6 #

Consideration Question: When making a gRPC call, a key step is to convert an object into a transferable binary format. However, in gRPC, instead of directly converting it into a byte array, we return an InputStream. Do you know the benefits of doing so?

During the underlying transmission process of RPC calls, Streams are also needed. By directly returning an InputStream instead of a byte array, data copying can be avoided.

Lecture 8 #

Thought question: Currently, when a service provider goes online, it will automatically register with the registry center. Service callers will automatically become aware of the newly added instances, and traffic will quickly be routed to these new instances. If I want to divert the traffic of certain service provider instances, besides taking them offline, have you thought of any other convenient methods?

There are several ways to solve this problem. For example, as mentioned in the comments, we can change the weight of the service provider instances to 0 or use routing.

However, the most convenient way to solve this problem is through dynamic grouping. In the Lecture 16, I explained the concept of business grouping, which can be used to achieve traffic isolation. If the business grouping is dynamic, we can freely adjust it through the management platform. Does this mean we can achieve dynamic traffic diversion? We will discuss this problem in detail in the advanced section. Please stay tuned.

Lecture 12 #

Thought question: In the entire process of RPC invocation, at which stage does exception retry occur?

Before answering this question, let’s review what we discussed in this lecture. When I talked about why RPC needs exception retry, I mentioned that if a network problem occurs when we send out a request and the request fails, we may need to retry the exception. From this, we can see that the exception retry operation needs to be performed on the client side. Because if a network problem occurs when the request is sent from the client side and the request fails, it is very likely that the request has not reached the server side, so the server side can’t handle the retry.

In addition, I also mentioned that when we initiate a retry and select a load-balanced node, we need to remove the node that encountered a problem before the retry in order to ensure the success rate of the retry. Therefore, the exception retry operation should happen before load balancing. When we initiate a retry, we will call the load balancing plugin to select a service node. When calling the load balancing plugin, we need to inform it to exclude the problematic service nodes.

In the entire process of RPC invocation, there are a series of steps from dynamic proxy to load balancing. If you have studied open source RPC frameworks, you will find that there is a filter chain before sending the request message on the client side. The request message is filtered step by step. After that, the load balancing plugin is called to select a service node and send the request message. The exception retry operation occurs after the filter chain processing and before calling the load balancing to select a service node. Such retries can reduce a lot of duplicate operations.

Lecture 14 #

Question for thought: In the section on preheating, we mentioned a problem, which is “when a large number of service providers are restarted, there is a high probability that requests will be sent to machines that have not been restarted. In this case, the service provider may not be able to handle it.” I don’t know how you view this issue and if there are any good solutions?

We can consider restarting the service during off-peak traffic periods to minimize impact. We can also consider restarting in batches, controlling the number of service nodes in each batch. When the weight and traffic of a batch of service nodes reach normal levels, we can then restart the next batch of service nodes.

Lesson 15 #

Thought Exercise: In the process of using RPC, businesses need to implement self-protection. Do you have any other solutions to this problem?

In this lesson, we learned that both the server and the client need to implement self-protection during RPC calls. The simplest and most effective way for a server to protect itself is through “rate limiting,” while the client can use the “circuit breaker” mechanism for self-protection.

In addition to “circuit breaking” and “rate limiting,” you may have also heard of the term “degradation.” Simply put, when a service is under a significant amount of requests and pressure, we can reduce some non-essential functionalities of the service in order to alleviate its load.

Another solution is through service governance, where we can reduce the weight of a service node to alleviate the request pressure on that specific service node, thus achieving the goal of protecting the service node.

Lecture 16 #

Thought Question: In our actual work, the work of testers and developers is generally carried out in parallel, which often leads to a problem: developers may need to start their own applications during the development process, while testers may need to deploy the same application in the testing environment for functional verification. If the interface group names used by developers and testers happen to be the same, in this case, it may interfere with the functional verification of other calling parties who are in the process of integration testing, thereby affecting the overall work efficiency. Do you have any good solutions to this situation?

One approach we can consider is to configure different registry centers. Developers can register their services with Registry Center A, while testers can register their services with a dedicated testing registry center, Registry Center B. In this way, when testers verify functionality, the calling party will pull the service nodes from Registry Center B. The developers’ restart of their services will not affect the testers.

If you have used or are familiar with Kubernetes, you must know the concept of “namespaces.” If an RPC framework supports “namespaces,” it can also solve this problem.

That’s all for today’s Q&A. If you have more questions, feel free to continue discussing in the comments section. See you in the next lecture!