With the development of the Internet, the scale of website applications keeps expanding, and the conventional vertical application architecture can no longer cope with it. The distributed service architecture and mobile computing architecture are imperative, and a governance system is urgently needed to ensure the orderly evolution of the architecture.

First, a picture

Speaking of Dubbo, I believe everyone will not be unfamiliar! Alibaba is an open source high-performance service framework, which enables applications to realize the output and input functions of services through high-performance RPC, and can integrate seamlessly with Spring framework.

Node roles:

  • Provider: exposes the service Provider of the service
  • Consumer: Service Consumer that invokes the remote service
  • Registry: A Registry where services are registered and discovered
  • Monitor: monitors the number and duration of service invocation
  • Container: service running Container

Second, implementation ideas

Today, we take the process of a user selecting a product and placing an order, split it into 3 business services: user center, product center, order center, and use Springboot + Dubbo to achieve a small Demo!

The service interaction flow is as follows:

This article mainly introduces Springboot and Dubbo framework integration and development practice, and the real business service separation is a very complex process, much more complex than we introduced this, the above mentioned three services are just for the project demonstration, do not bother too much why such separation!

Ok, nonsense is not much to say, below we open masturbation!

  • 1. Create four centos7s on the VM and install ZooKeeper on any of them
  • 2. Build microservice projects and write code
  • 3. Deploy microservices on centos7
  • 4. Remote service invocation test

Zookeeper installation

Before using Dubbo, we need a registry. Currently, there are registries available for Dubbo, such as ZooKeeper, Nacos, etc. Zookeeper is generally recommended!

Before installing Zookeeper, you need to install and configure JDK. Oracle Java8 SE is used on the local computer.

  • Install JDK (already installed and can be ignored)
Yum -y install Java -- 1.8.0 comes with itsCopy the code
  • Check the Java installation
java -version
Copy the code

  • After installing the JDK, download and install Zookeeper
Create a ZooKeeper foldercd/usr mkdir Zookeeper Downloads wget of ZooKeeper-3.4.14 http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz extract tar ZXVF. - Zookeeper - 3.4.14. Tar. Gz < / pre >Copy the code
  • Create data and log directories
Create directories for storing data and logscd /usr/zookeeper/
mkdir data
mkdir logConf file zoo_sample. CFG and rename it zoo.cfgcd conf/
cp zoo_sample.cfg zoo.cfg</pre>
Copy the code
  • Configuration zookeeper
# edit zoo. CFG file
vim zoo.cfg
Copy the code

  • Start the Zookeeper
# start the Zookeeper
./zkServer.sh start

# Query the Zookeeper status
./zkServer.sh status

# Disable the Zookeeper state
./zkServer.sh stop</pre>
Copy the code

If the following information is displayed, the startup is successful.

Iv. Project Introduction

  • Springboot version: 2.1.1.release
  • Zookeeper version: 3.4.14
  • Dubbo version: 2.7.3
  • Mybtais-plus version: 3.0.6
  • Database: mysqL-8
  • Build tool: Maven
  • Service module: user center, commodity center, order center

5. Code practice

5.1. Initialize the database

First, on the mysql client, create three databases, namely, Dianshang-user, Dianshang-platform and dianshang-Business.

  • In the Dianshang-user database, create the user table TB_user and initialize the data

  • In the Dianshang-platform database, create the commodity table TB_product and initialize the data

  • In the Dianshang-platform database, create the order table TB_ORDER and order detail table tb_ORDER_detail

5.2. Create a project

After the database table design is complete, create a Springboot project named DianShang under IDEA.

The final directory is as follows:

Directory structure description:

  • Dianshang-common: mainly houses some common libraries that all services can rely on
  • Dianshang-business: Order center, whereapiThe module mainly provides the Dubbo service exposure interface,providerA module is aspringbootProject to provide service processing operations
  • Dianshang-user: user center, whereapiThe module andproviderModule, designed similarly
  • Dianshang-platform: Merchandise center, whereapiThe module andproviderModule, designed similarly

Add dubbo and ZooKeeper clients to the parent POM file and make them available to all dependent projects.

<! -- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> The < version > 1.18.4 < / version > < scope > provided < / scope > < / dependency > <! -- Dubbo Spring Boot Starter --> <dependency> <groupId>org.apache.dubbo</groupId> < artifactId > dubbo - spring - the boot - starter < / artifactId > < version > 2.7.3 < / version > < / dependency > <! -- Using ZooKeeper as the registry, Zookeeper </groupId> <artifactId> Zookeeper </artifactId> <version>3.4.13</version> <exclusions> <groupId>org.slf4j</groupId> <artifactId> slf4J-api </artifactId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId>
            <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency> <! > <dependency> <groupId>org.apache.curator</groupId> < artifactId > curator - framework < / artifactId > < version > 4.2.0 < / version > < / dependency > < the dependency > < the groupId > org. Apache. Curator < / groupId > < artifactId > curator - recipes < / artifactId > < version > 4.2.0 < / version > < / dependency >Copy the code

Tips: For example, in this example, the ZooKeeper server version is 3.4.14. Therefore, the zooKeeper file library should be the same as the zooKeeper file library. If you rely on the 3.5.x version of ZooKeeper, the project will start with all kinds of bogey errors!

5.3. Create a User center project

In IDEA, create the Dianshang-user submodule and rely on the Dianshang-common module

<dependencies> <dependency> <groupId>org.project.demo</groupId> <artifactId>dianshang-common</artifactId> The < version > 1.0.0 < / version > < / dependency > < / dependencies >Copy the code

Meanwhile, dianshang-user-provider and Dianshang-user-API modules are created.

  • Dianshang-user-api: mainly provides interface exposure to other services
  • Dianshang-user-provider: similar to a Web project, mainly responsible for basic servicescrudWhile relying ondianshang-user-apiThe module

5.3.1. Configure the Dubbo service

Configure the dubbo service in the application. Yml file of dianshang-user-provider as follows:

User center service port
server:
 port: 8080
# data source configuration
spring:
 datasource:
 druid:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: "jdbc:mysql://localhost:3306/dianshang-user"
 username: root
 password: 111111
# dubbo configuration
dubbo:
 scan:
    Write the package name according to your actual situation
 base-packages: org.project.dianshang.user
 protocol:
 port: 20880
 name: dubbo
 registry:
    #zookeeper registration center addressAddress: zookeeper: / / 192.168.0.107:2181Copy the code

5.3.2. Write service exposure interfaces and implementation classes

In the dianshang-user-API module, create a UserApi interface and return the parameter object UserVo!

Public interface UserApi {/** * query user information * @param userId * @return
     */
    UserVo findUserById(String userId);
}
Copy the code

UserVo needs to be serialized as follows:

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true) public class UserVo implements Serializable { private static final long serialVersionUID = 1L; /** * userId */ private String userId; /** * private String userName; }Copy the code

In the Dianshang-user-Provider module, write the UserApi interface implementation class as follows:

@Service(interfaceClass =UserApi.class)
@Component
public class UserProvider implements UserApi {

    @Autowired
    private UserService userService;

    @Override
    public UserVo findUserById(String userId) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.eq("user_id",userId);
        User source = userService.getOne(queryWrapper);
        if(source! = null){ UserVo vo = new UserVo(); BeanUtils.copyProperties(source,vo);
            return vo;
        }
        returnnull; }}Copy the code

The annotation @ Service refers to the org. Apache. Dubbo. Config. The annotation. Under the Service annotations, rather than under the Spring annotations!

Next, let’s go ahead and create the Goods Center project!

5.4. Create commodity Center project

Similar to the user-centric project, in IDEA, the Dianshang-platform submodule is created and relies on the Dianshang-common module

<dependencies> <dependency> <groupId>org.project.demo</groupId> <artifactId>dianshang-common</artifactId> The < version > 1.0.0 < / version > < / dependency > < / dependencies >Copy the code

Meanwhile, the dianshang-platform-provider and dianshang-platform-API modules are created.

  • Dianshang-platform-api: mainly provides interface exposure to other services
  • Dianshang-platform-provider: similar to a Web project, mainly responsible for basic servicescrudWhile relying ondianshang-platform-apiThe module

5.4.1 configuring the Dubbo service

Configure the dubbo service in the application. Yml file of dianshang-platform-provider as follows:

User center service port
server:
 port: 8081
# data source configuration
spring:
 datasource:
 druid:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: "jdbc:mysql://localhost:3306/dianshang-platform"
 username: root
 password: 111111
# dubbo configuration
dubbo:
 scan:
    Write the package name according to your actual situation
 base-packages: org.project.dianshang.platform
 protocol:
 port: 20881
 name: dubbo
 registry:
    #zookeeper registration center addressAddress: zookeeper: / / 192.168.0.107:2181Copy the code

5.4.2. Write service exposure interfaces and implementation classes

In the dianshang-platform-API module, create a ProductApi interface and return the parameter object ProductVo!

Public interface ProductApi {/** * Query product information * @param productId * @ by commodity IDreturn
     */
    ProductVo queryProductInfoById(String productId);
}
Copy the code

ProductVo needs to be serialized as follows:

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true) public class ProductVo implements Serializable { private static final long serialVersionUID = 1L; /** ID*/ private String productId; /** private String productName; /** private BigDecimal productPrice; }Copy the code

In the dianshang-platform-Provider module, write the ProductApi interface implementation class as follows:

@Service(interfaceClass = ProductApi.class) @Component public class ProductProvider implements ProductApi { @Autowired private ProductService productService; @override public ProductVo queryProductInfoById(String productId) {// Query Product information by Product IDsource = productService.getById(productId);
        if(source! = null){ ProductVo vo = new ProductVo(); BeanUtils.copyProperties(source,vo);
            return vo;
        }
        returnnull; }}Copy the code

Next, we continue to create the order center project!

5.5. Create an order Center project

Similar to the Goods Center project, in IDEA, the Dianshang-Business submodule is created and relies on the Dianshang-common module

<dependencies> <dependency> <groupId>org.project.demo</groupId> <artifactId>dianshang-common</artifactId> The < version > 1.0.0 < / version > < / dependency > < / dependencies >Copy the code

Meanwhile, dianshang-business-Provider and Dianshang-business-API modules are created.

  • Dianshang-business-api: primarily provides interface exposure to other services
  • Dianshang-business-provider: Similar to a Web project, mainly responsible for the basic businesscrudWhile relying ondianshang-business-apiThe module

5.5.1. Configure the Dubbo service

Configure the dubbo service in the application. Yml file of dianshang-business-provider as follows:

User center service port
server:
 port: 8082
# data source configuration
spring:
 datasource:
 druid:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: "jdbc:mysql://localhost:3306/dianshang-business"
 username: root
 password: 111111
# dubbo configuration
dubbo:
 scan:
    Write the package name according to your actual situation
 base-packages: org.project.dianshang.business
 protocol:
 port: 20882
 name: dubbo
 registry:
    #zookeeper registration center addressAddress: zookeeper: / / 192.168.0.107:2181Copy the code

5.5.2. Write service exposure interfaces and implementation classes

In the dianshang-business-API module, create an OrderApi interface and return the parameter object OrderVo!

Public interface OrderApi {/** * query user order information by userId * @param userId * @return
     */
    List<OrderVo> queryOrderByUserId(String userId);
}
Copy the code

Where OrderVo needs to implement serialization as follows:

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true) public class OrderVo implements Serializable { private static final long serialVersionUID = 1L; /** orderId */ private String orderId; /** order number */ private String orderNo; /** Order amount */ private BigDecimal orderPrice; /** orderTime */ private Date orderTime; }Copy the code

In the Dianshang-business-Provider module, write the OrderApi interface implementation class as follows:

@Service(interfaceClass = OrderApi.class) @Component public class OrderProvider implements OrderApi { @Autowired private  OrderService orderService; @Override public List<OrderVo> queryOrderByUserId(String userId) { QueryWrapper<Order> queryWrapper = new QueryWrapper<Order>(); queryWrapper.eq("user_id",userId);
        List<Order> sourceList = orderService.list(queryWrapper);
        if(! CollectionUtils.isEmpty(sourceList)){
            List<OrderVo> voList = new ArrayList<>();
            for (Order order : sourceList) {
                OrderVo vo = new OrderVo();
                BeanUtils.copyProperties(order, vo);
                voList.add(vo);
            }
            return voList;
        }
        returnnull; }}Copy the code

At this point, service exposure interfaces have been developed for three projects! Next we’ll write how to make a remote call!

5.6. Remote Invocation

5.6.1 Write and create order service

In the dianshang-business-provider module, dianshang-business-API and dianshang-user-API are first relied on before writing and creating the order interface, as follows:

<! <dependency> <groupId>org.project.demo</groupId> <artifactId>dianshang-platform-api</artifactId> The < version > 1.0.0 < / version > < / dependency > <! --> <dependency> <groupId>org.project.demo</groupId> <artifactId>dianshang-user-api</artifactId> The < version > 1.0.0 < / version > < / dependency >Copy the code

In the dianshang-business-provider module, write the order creation service as follows:

@RestController
@RequestMapping("/order")
public class OrderController {

	@Autowired
    private OrderService orderService;

	@Autowired
	private OrderDetailService orderDetailService;

    @Reference(check =false)
	private ProductApi productApi;

    @Reference(check =false) private UserApi userApi; /** * new */ @jwtignore @requestMapping (value ="/add")
	public boolean add(String productId,String userId){
	    LocalAssert.isStringEmpty(productId,"Product Id cannot be empty");
        LocalAssert.isStringEmpty(userId,"User Id cannot be empty");
        ProductVo productVo = productApi.queryProductInfoById(productId);
        LocalAssert.isObjectEmpty(productVo,"No product information found");
        UserVo userVo = userApi.findUserById(userId);
        LocalAssert.isObjectEmpty(userVo,"No user information found");
        Order order = new Order();
        order.setOrderId(IdGenerator.uuid());
        order.setOrderNo(System.currentTimeMillis() + "");
        order.setOrderPrice(productVo.getProductPrice());
        order.setUserId(userId);
        order.setOrderTime(new Date());
        orderService.save(order);

        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderDetailId(IdGenerator.uuid());
        orderDetail.setOrderId(order.getOrderId());
        orderDetail.setProductId(productId);
        orderDetail.setSort(1);
        orderDetailService.save(orderDetail);
		return true; }}Copy the code

@ the Reference of these comments, it is to belong to org. Apache. Dubbo. Config. The annotation. The Reference of the annotations, said remote depend on service.

Check =false indicates that the remote service status check is not performed when the service is started. The purpose of setting this parameter is to prevent the current service startup failure. For example, the user center project is not started successfully, but the order center depends on the user center.

5.6.2 Compile users to query their own order information

Similarly, dianshang-user-provider module relies on Dianshang-business-API and Dianshang-user-API before writing the interface for users to query their own order information, as follows:

< the groupId > org. Project. The demo < / groupId > < artifactId > dianshang - business - API < / artifactId > < version > 1.0.0 < / version > </dependency> <dependency> <groupId>org.project.demo</groupId> <artifactId>dianshang-user-api</artifactId> <version>1.0.0</version> </dependency></pre> In the 'dianshang-user-provider' module, write an interface for users to query their own order information, as follows: <p style=" margin-bottom: 0.5em; font-family: Menlo, Monaco, Consolas, &quot; Courier New&quot; , monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; 1.5 em margin: 0 px 0 px; font-size: 14px; The line - height: 1.5 em. word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;" >@RestController @RequestMapping("/user") public class UserController { @Reference(check =false) private OrderApi orderApi; /** * by user ID, * @param userId * @return */ @requestMapping ("/list") public list <OrderVo> queryOrderByUserId(String userId){ return orderApi.queryOrderByUserId(userId); }}Copy the code

At this point, the remote service invocation is written!

Six, service test

Before deploying the project to the server, let’s test locally to see if all the services work.

  • Start the User Centerdianshang-user-provider

  • Continue to launch the commodity centerdianshang-platform-provider

  • Then start the order centerdianshang-business-provider

Finally, let’s test whether the service interface works as expected.

Open a browser, type http://127.0.0.1:8082/order/add? ProductId =1&userId=1 test create order interface, page running results display normal!

Let’s look at the database, is the order generated?

Ok! Very clear to see, the data has gone in, no problem!

We’ll test the orders in the center of the user query interface, enter http://127.0.0.1:8080/user/list? UserId =1, the page runs as follows!

At this point, the local service test has basically passed!

7. Server deployment

Now that we’ve covered building, developing, and testing services, how do you deploy them on the server side?

First of all, modify the application. Yml file of each project, change the data source address and Dubbo registry address to the online connected address, and then use maven tool under the dianshang directory to execute the following command to package the whole project!

mvn clean install

You can also use maven to configure clean install for package execution in the IDEA environment.

Copy dianshang-user-provider. Jar, dianshang-platform-provider. Jar, and Dianshang-business-provider.

This server uses CentOS7. There are four servers in total, one of which deploys ZooKeeper and the other three deploys three microservice projects.

Log in to the server and enter the following command to ensure that the JDK is installed!

java -version

Turn off the firewall on all servers and allow port access!

systemctl stop firewalld.service
Copy the code

Systemctl disable firewalld.service

  • The user center service is startedservice.log(VM IP address: 192.168.0.108)

nohup java -jar dianshang-user-provider.jar > service.log 2>&1 &

  • The commodity center service is started, and the log information is output toservice.log(VM IP address: 192.168.0.107)

nohup java -jar dianshang-platform-provider.jar > service.log 2>&1 &

  • The order center service is started and the log information is output toservice.log(VM IP address: 192.168.0.109)
nohup java -jar  dianshang-business-provider.jar > service.log 2>&1 &
Copy the code

Open a browser, type http://192.168.0.109:8082/order/add? ProductId =1&userId=1 test create order interface, page running results display normal!

We’ll test the orders in the center of the user query interface, enter http://192.168.0.108:8080/user/list? UserId =1, the page runs as follows!

You can clearly see the output of two messages, the second order is generated by the test environment server and the first is generated by the local development environment.

At this point, the server deployment is almost complete!

In a production environment, multiple ZooKeeper servers may be required to ensure high availability, at least two servers to deploy service services, and routing through load balancing.

Eight, summary

The whole article is quite long, mainly around the integration of SpringBoot + Dubbo. Remote service invocation via annotation development is as easy as traditional SpringMVC development. Of course, dubbo service invocation via XML configuration is also possible, which will be covered later.

At the same time, it also introduces the deployment of the server, from which we can see that although the development is simple, how to ensure the high availability of the service has become the top task of the developers because of the distributed deployment. Therefore, although the development of distributed micro-service is simple, how to ensure the high availability of the deployed service? Operation and maintenance will bring many challenges!