preface

Dear brothers, this article records an Jiang’s difficult interview questions in a public e-commerce company in Guangzhou. Ann sauce because this is true did not review, so also answered about (lonely). I don’t know if it is due to the public mall, there is no such issue as high concurrency, but there is a question about multi-threading. The following interview questions have been answered.

At 2021-03-02, the HR informed me that I passed the interview, but I refused because the salary offered did not meet my expectations. . Is this the beginning of me becoming a face bully?

How can MQ sequential consumption be guaranteed

Since The familiar MQS mentioned in Anjak’s resume are RabbitMQ and RocketMQ, the wave is analyzed with these two MQS.

Sequential consumption is guaranteed in RabbitMQ

Since RabbitMQ does not support sequential consumption, there can be consumption chaos when there are multiple consumers in a queue.

The solution

The producer sends the messages in MQ point-to-point mode, meaning that each queue corresponds to one consumer, and then sends the messages in order to the same queue.

The consumer needs to turn off Autoack, set prefetchCount to one, consume one message at a time, process it manually, and then receive the next message. Since there is only one consumer, this ensures sequential consumption.

Sequential consumption is guaranteed in RocketMQ

Since RocketMQ itself supports sequential consumption, here’s a quote from the official website.

Message ordering means that messages can be consumed in the order in which they are sent (FIFO). RocketMQ ensures strict message ordering, either partitioned or globally ordered. By default, messages are sent to different queues (partitioned queues) in Round Robin mode. When consuming messages, they are pulled from multiple queues, so the order of sending and consuming is not guaranteed. But if you control the order in which messages are sent, they are only sent to the same queue, and only pulled from that queue when consumed, the order is guaranteed. If there is only one sending and consuming queue, it is globally ordered. If more than one queue participates, the partition is ordered, that is, the messages are ordered relative to each queue.

How does a producer ensure that messages are sent sequentially to a queue? For example, the same order can be sent to the same queue after passing the algorithm and then sent synchronously. If only the creation message of the same order is sent successfully, the payment message can be sent. In this way, we ensure that the delivery is orderly.

For consumers, MessageListenerOrderly interface is mainly implemented and Consumer is set to start consumption from the head of queue or the end of queue for the first time. If it is not started for the first time, Then according to the last position to continue consumption (consumer. SetConsumeFromWhere (ConsumeFromWhere. CONSUME_FROM_FIRST_OFFSET)).

A brief description of how MySQL executes a SQL statement

This one is still very complicated, so let’s make it simple. Take the query statement, which is slightly different from the new statement, as shown in the following figure.

The connector

Before querying SQL statements, you must establish a connection to MySQL, which is done by the connector. Connectors establish connections to clients, obtain permissions, and maintain and manage connections

The query cache

After the connection is established, the SELECT statement is executed, first by querying the cache.

When MySQL receives a query request, it will first check the cache to see if the statement was executed. Executed statements and their results are stored as key-value pairs in an area of memory. Key is the query statement and value is the query result. If your query can find the key directly in the cache, the value will be returned directly to the client.

If the statement is not in the query cache, subsequent execution phases continue. After the execution is complete, the results are stored in the query cache. If the query matches the cache, MySQL does not need to perform complex operations and can directly return the result, which improves efficiency.

analyzer

If the query cache is not hit, statement execution begins. First, MySQL needs to parse SQL statements.

The parser first does a lexical analysis. SQL statements are composed of multiple strings and Spaces. MySQL needs to identify what the strings are and what they represent. MySQL recognizes this from the keyword select that you enter. This is the query. It also recognizes the string user_info as a table name and the string ID as a column name. Then you have to do the grammar analysis. Based on the result of lexical analysis, the parser determines whether the entered SQL statement meets the MySQL syntax based on the syntax rules.

The optimizer

After lexical analysis and syntax analysis by the analyzer, it is also processed by the optimizer.

The optimizer determines which index to use when there are multiple indexes in a table, or the order in which tables are joined when a statement has multiple table joins.

actuator

MySQL knows what to do from the parser, and knows how to do it from the optimizer, so it enters the executor phase and starts executing statements.

To start execution, check whether you have permission to perform query on user_info. If you do not have permission, an error will be returned. If you have permission, open the table and continue. When a table is opened, the executor calls the corresponding engine’s read interface based on the table’s engine definition.

Redis String underlying data structure

Redis is written in C, but for Redis strings, it is not a C string (that is, an array of characters ending with a null character \0).

USES aSDS(simple dynamic string), the data format is shown in the following figure.

  1. freeRecord thebufThe number of unused bytes in the array.
  2. lenSave theSDSSaves the length of the string.
  3. buf[]Arrays are used to hold each element of a string.

advantages

The advantages of using SDS are as follows:

Constant complexity gets the length of the string

Due to the existence of len attribute, we only need to read len attribute to obtain the length of SDS string, and the time complexity is O(1). For C language, obtaining the length of the string is usually achieved through traversal counting, and the time complexity is O(n). The strlen key command is used to obtain the string length of the key.

Prevent buffer overflow

We know that the strcat function used in C to concatenate two strings will cause a buffer overflow if not enough memory space is allocated. For SDS data type, during character modification, it will check whether the memory space meets the requirements according to the len attribute of the record first. If not, the corresponding space will be expanded, and then the modification operation will be carried out, so buffer overflow will not occur.

Reduce the number of memory reallocations for modifying strings

C does not record the length of the string. Therefore, if you want to modify the string, you must reallocate the memory (free and then apply). If you do not reallocate the string, the memory buffer will overflow when the string length increases, and the memory will leak when the string length decreases.

As for SDS, due to the existence of len attribute and free attribute, SDS realizes two strategies of space pre-allocation and lazy space release for modifying string:

1. Space preallocation: When you expand the space of a string, the expanded memory is larger than the actual memory, which reduces the number of memory reallocation required for continuous string growth operations.

2. Lazy space release: When a string is shortened, the program does not immediately use memory reallocation to reclaim the excess bytes. Instead, it uses the free property to record the number of bytes and wait for future use. (SDS also provides an API for manually releasing unused space when needed.)

Binary security

Because the C string is marked by a null character as the end of the string, and for some binary files (such as pictures, etc.), the content may contain an empty string, so the C string cannot be accessed correctly. All SDS apis deal with elements in buF in binary terms, and SDS does not judge the end of the string by the empty string, but by the length represented by the Len attribute.

Compatible with some C string functions

Although SDS is binary safe, it also follows the convention that every string ends in an empty string, which makes it possible to reuse some functions from the C library

.

Summarize the characteristics of microservices in a few words

Single responsibility, team independence, technology independence, front-end separation, database separation, independent deployment, service governance

${}, #{} difference and principle in mybatis

#{} is a parameter placeholder, a parameter marker in JDBC precompiled statements.

${} is just a string substitution that will take place during the dynamic SQL parsing phase.

The difference is that when setting parameters, #{} replaces them as strings (with double quotes). ${} simply replaces the variable with the parameter value, which is where Sql injection comes in.