I. Introduction
The author was responsible for the development of the vivo app store server and was fortunate to witness the development of the app store from one million daily activities to tens of millions of daily activities. After the application store client has gone through hundreds of iterations of large and small versions, the server has also completed the architecture from the single to service cluster and microservice upgrade.
The following will mainly talk about some experience and insights about the problems encountered by the server in the API of different versions of the client in the process of rapid business development, the continuous iteration of the product. On the one hand, let the children's shoes in the team have a more thorough understanding of some of the existing design ideas, on the other hand, it is also hoped that it can resonate with colleagues in similar scenarios and provide solutions.
Two, general solution
The app store client is iterated very frequently. When a new APP version is released, it will inevitably lead to multiple versions, so that the server will cause multiple different client requests. Forcing users to upgrade the APP may result in loss of users, so it is necessary to adopt multiple versions to coexist. The following is a reference of some SOA service API version control methods discussed in the industry [1]. In principle, the following three solutions are indispensable in actual development.
Solution 1: The Knot has no version -that is, there is always only one version of the platform's API, and all users must use the latest API. Any API modification will affect all users of the platform. (Figure 1 below)
plan two: Point-to-Point -point-to-point, that is, the API version of the platform comes with its own version number. Users can choose to use the corresponding API according to their needs. New API features are required and users must upgrade by themselves. (Figure 2 below)
Solution Three: Compatible Versioning -Compatible Versioning. Like The Knot, the platform has only one version, but the latest version needs to be compatible with the API behavior of the previous version. (Figure 3 below)
(Quoted from: The Costs of Versioning an API )
Simple analysis, The Knot only maintains the latest version, which is somewhat simplified for the server, but requires service users to adapt to the latest version in time. This approach is not suitable for user products. At present, internal services are more suitable. Point-Point provides independent services for different customer versions. As the version increases, the cost of development and operation and maintenance will increase. This is used when we face "protocol upgrades" later.
Option 3 should be the most commonly used case, and the server is backward compatible. The following cases also mainly adopt this kind of thinking, and there are many specific methods. Different strategies will be used in combination with specific business scenarios. This will be the focus of the next discussion.
3. Challenges and explorations faced by specific business scenarios
3.1 Application scenarios of The Knot without version and Point-to-Point mode
The above picture is a microcosm of the iterative changes of our app store. The business development to a certain stage faces the following challenges:
1) In the early stage of business development, as a service provider, the server must not only support multiple versions of the application store client, but also serve the PC assistant on the software side;
2) The product form changes diversified, and the change and maintenance of the server interface faces the challenge of multi-version client compatibility;
3) In terms of architecture logic, the server adopts the early traditional architecture, and the development and maintenance costs are relatively high; the protocol for the interaction between the server and the client is optimized and upgraded; and service splitting is imperative.
Therefore, server-side agreements, framework upgrades, and public service splitting are the primary solutions. The transformation has gone through two processes:
- phase one new version and new interfaces all adopt the new JSON protocol; existing functional interfaces are compatible, differentiated according to the client version, and return the format content of different protocols.
- Phase two With the business iteration, all interfaces that the new version of the store relies on have completed the protocol upgrade. In order to improve the stability of the service, the performance of the old protocol cannot be significantly improved. On the one hand, the back-end architecture and framework are upgraded, and the development is improved. Efficiency and maintainability. At the same time, split and independent new projects to realize that historical projects are only available for historical versions. We split independent services for large traffic, high concurrency, and basic service scenarios such as homepage, details, and downloads. At the same time, some public internal RPC services are also extracted, such as obtaining application details, filtering services, etc.
After transformation, the server-side architecture is shown in the figure above.
1) At this point, Old-Service only needs to perform corresponding maintenance work, corresponding to the Point-to-Point version.
2) Since the internal RPC service only provides internal services, the server and client can be upgraded at any time, as long as the latest version is maintained, using The Knot mode. It should be noted here that the service upgrade needs to pay attention to maintaining backward compatibility, and special care needs to be taken when extending or modifying fields, otherwise it may cause abnormal client calls when the service is upgraded.
3.2 Compatible Versioning: Compatible Versioning
Compatibility version control should be the most common version control method, especially in the C/S architecture. The strategies for different specific compatibility versions are summarized as API version, client version number, function parameter flags, etc.
Scenario 1: API version number control
With the development of the Internet, user experience requirements are getting higher and higher, and the product form will also change differently every year. In addition to avoiding aesthetic fatigue, we are also constantly exploring how to improve screen efficiency, click-through rates, and conversions. Take the homepage list of the app store as an example.
The application list has experienced a single application double row -> single row -\> single row + interspersed layout in form. The content has also undergone evolution from different commercialization models, manual scheduling to algorithms.
The internal logic changes of each version of the interface are very large, and there are obvious differences. If you simply judge and process based on the version at the service layer, the processing logic will become extremely complicated, and it may also cause an impact on the lower version. At the same time, the store homepage is a very important business scenario. Considering risk considerations, for scenarios like this, a version field is added to the interface URL. Different values are used for different versions. Different processing logics will be more in the control layer according to different versions. Reasonable, simple and effective. Specific strategies also include adding the interface version field /{version}/index to the URL, and the request header carrying version parameters.
Scenario 2: Client version number control
Similar to the homepage list, the interspersed banner of the store has also undergone multiple iterations. As shown below. These interspersed styles all appear in different versions. The support level of each version is different in terms of style layout, support jump ability, etc., and corresponding processing adaptation, filtering and other processing are required when the interface returns.
This kind of scenario can be solved if the scenario 1 is used to upgrade the new interface, but there will be a lot of duplicate code, and the new interface will affect the big data buried point statistics for the client interface modification, especially some interface paths. Relatively high communication and maintenance costs are in it.
In order to improve code reusability. The use of client version number control is the preferred strategy. However, it should be noted that if you simply judge based on the client version number at the code level, there will be the following issues that need to be considered:
1) There will be various judgments at the code level, resulting in poor code readability, is there a more elegant method;
2) There is an objective situation. That is, the version number of the client is uncertain. As the client uses the train release model reference [2], multiple versions are developed in parallel, resulting in changes in version numbers and discontinuous version jumps from time to time, which also brings a lot of trouble to the development of the server.
How to think about solving these problems? In fact, for some resources or product modules involved in different product forms that appear in different iteration cycles, it can be considered that they have the attributes of version or time. From the perspective of the programmer, consider the client version supported by a certain resource as a member attribute of the resource object. After each resource has this attribute, it also has corresponding logical behavior to correspond to the member method---filter according to the attribute. After this design gives the resource attributes and behaviors, the resource has a unified and flexible filtering capability, instead of a simple hard-coded if-else judgment based on the version.
Once you have a plan, it will be easier to implement. Develop and allocate resource ID, and set the corresponding support client version range. The filtering logic is unified to the resource object.
At the code level, the filtering logic can be uniformly encapsulated into a tool class (sample code), and filtered in each business interface return. A more elegant solution is to establish a unified resource upper-level class, encapsulate the resource filtering method, and all resource objects in the resource position implement the upper-level class, and achieve the filtering ability in the unified resource acquisition logic.
Scenario 3: New function identification parameter
The application store business mainly provides users with discovering and downloading new applications, and updating the applications installed on the mobile phone. Incremental updates in the store can reduce the size of the update package, so it is also called a traffic-saving update, which effectively improves the user experience. In the early stage, we used an open source incremental algorithm, but found that the algorithm will take a long time to synthesize and split packages in some machines, and even cause crashes.
So the project team sought a more efficient splitting algorithm. Similar to the scenarios where the functions of these existing interfaces are enhanced, are there any better solutions besides providing new APIs or simply extending internally through client version judgment? Because in addition to the known drawbacks of these solutions, long-term considerations are needed. For example, the algorithm mentioned above will not be upgraded in the future, and will the download interface have more capabilities.
flag parameter field is added to the original interface to indicate the capabilities supported by the client that sent the request. For subsequent expansion, the field type is an integer value, not just a simple boolean, the server completes the judgment logic -bit operation. The client also gets rid of the strong consistency between a certain function and the version, and does not need to record that a certain version has certain capabilities.
Fourth, more thoughts on interface design
Finally, add some stepped pits and reflections. When the server provides an interface, it can't just focus on the implementation of the interface. More often, it needs to focus on the users of the interface, the scenarios they use, the timing of invocations, and so on. Otherwise, the time it takes for development to troubleshoot and maintain the interface will be several times longer than the actual development time.
1) scene-based : What is scene-based? Take the store client to help users detect whether the application version installed on the mobile phone is the latest service. The detection timing is different in different scenarios, such as user activation and user switching wlan environment , Timing detection, etc. When a refined analysis is required, which requests are valid and which will cause centralized requests, at this time, if there is no scene distinction on the request, then the analysis will be impossible to start. So when communicating with the client interface design, please bring the scene as a factor. For interface design, you can refer to /app/{scene}/upgrade, define the name of each scene, and bring specific scenes on the path, which will be of great benefit to the magnitude of requests and problem analysis from different sources online.
2) authentication and service isolation : In addition to the scenario needs to be considered, the interface call shall be recorded and authenticated and service isolation shall be done during allocation. For example, part of the interface services of the store are not only provided to the client, but also provided to the mobile phone system application call. At present, there are hundreds of millions of users in vivo. Be very careful here. The amount of system application calls is improperly controlled, and the concurrency is much larger than the store itself. First, evaluate and communicate with the service caller in the early stage, and do a good job design to avoid problems. Even when there is a problem, there must be a mechanism to quickly find the problem, analyze the source of the problem, and reduce the loss caused by the problem.
So far, the above ideas to solve the problem have a certain relationship with the specific business and background. With the continuous iteration and development of technology and the dynamics of mobile APP pages, the industry now has more efficient technical solutions, such as Google's Flutter and Weex. These technologies can achieve flexible expansion, multi-end unification, and performance can be close to native. This not only reduces the frequency of client-side publishing, but also reduces the cost of server-side compatibility processing. At present, our vivo team is also using and practicing.
Technology is constantly changing, and there is no best solution, only the most suitable solution. The development process not only satisfies the current implementation, but also considers subsequent scalability and maintainability. development can not blindly pursue high-end technology, technology ultimately serves the business, adhere to the long-term principle, efficiency first .
Five, reference materials
1、The Costs of Versioning an API
2. agile development, train release model
Author: vivo Internet server team-Song jie
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。