ZooKeeper与Dubbo注解配置

1,294 阅读5分钟

今天来聊一聊分布式框架。介绍一下ZooKeeper与Dubbo。

下载链接:ZooKeeper

  • 二进制文件,下载这个 apache-zookeeper-3.5.5-bin.tar.gz
  • 源码,要研究源码,可以下这个 apache-zookeeper-3.5.5.tar.gz

Mac下使用ZooKeeper(单点模式)

  • 修改zookeeper/conf下的zoo_sample.cfg文件,将zoo_sample.cfg重命名为zoo.cfg
  • cd到当前目录 终端下执行 zkServer start
  • 查看状态 zkServer status
  • 连接到zk,zkCli -server localhost

zk

下面是zk中的一些命令,日常工作基本不会用到。有查看节点,新增节点,修改节点,删除节点。

命令

quit

ZooKeeper中的角色

角色 描述
领导者(leader) 负责投票的发起和决议,更新系统状态
学习者(learner)-跟随者(follower) 接收客户端请求并向客户端返回结果,在选主过程中参与投票
学习者(learner)-观察者(observer) 可以接收客户端连接,将请求转发给leader节点,但是不参与投票过程,
只同步leader状态,observer是为了扩展系统,提高读取速度
客户端(client) 请求发起方

Dubbo

节点角色说明

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

调用关系说明

  • 服务容器负责启动,加载,运行服务提供者。
  • 服务提供者在启动时,向注册中心注册自己提供的服务。
  • 服务消费者在启动时,向注册中心订阅自己所需的服务。
  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

现在SpringBoot都更新到2.0版本了,就用注解配置吧。不用xml了...

嗯,简单一点,不用数据库了

project

依赖

  • 配置好Swagger,全局异常拦截器

    配置好Swagger

  • 添加api模块

    添加api模块

  • 最后的结构

    最后的结构

gradle:build.gradle

allprojects {
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'maven'
    apply plugin: 'eclipse'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: "io.franzbecker.gradle-lombok"

    group = 'com.ler.dubbo'
    version = '1.0.0-SNAPSHOT'
    sourceCompatibility = '1.8'

    jar.enabled = true

    configurations {
        developmentOnly
        runtimeClasspath {
            extendsFrom developmentOnly
        }
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'

        //dubbo zk
        compile group: 'com.alibaba', name: 'dubbo', version: '2.6.1'
        compile(group: 'com.101tec', name: 'zkclient', version: '0.10') {
            exclude group: 'log4j', module: 'log4j'
            exclude group: 'org.slf4j', module: 'slf4j-api'
            exclude group: 'org.slf4j', module: 'slf4j-log4j12'
        }
        compile('org.apache.curator:curator-recipes:4.0.1') {
            exclude group: 'org.apache.zookeeper', module: 'zookeeper'
        }
    }
}

buildscript {
    ext {
        springBootVersion = '2.0.2.RELEASE'
    }
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath "io.franzbecker:gradle-lombok:1.14"
    }
}

dependencies {

    compile project(":api")

    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'


    compile group: 'com.alibaba', name: 'fastjson', version: '1.2.55'
    compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'

    compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
    compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'

}

因为没有数据库,所以application.properties配置简单了很多。 为了防止冲突,只有一个端口配置

server.port=8081

swagger 配置

package com.ler.dubbo.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author lww
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer {

	@Bean
	public Docket api() {
		return new Docket(DocumentationType.SWAGGER_2)
				.forCodeGeneration(true)
				.select()
				.apis(RequestHandlerSelectors.basePackage("com.ler.dubbo.demo.controller"))
				.build()
				.apiInfo(apiInfo());
	}

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder().title("Dubbo Demo").description("接口文档").version("1.0.0-SNAPSHOT").build();
	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/**")
				.addResourceLocations("classpath:/static/");
		registry.addResourceHandler("swagger-ui.html")
				.addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**")
				.addResourceLocations("classpath:/META-INF/resources/webjars/");
	}

}

DubboConfiguration

package com.ler.dubbo.demo.config;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ConsumerConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author lww
 * @date 2019-08-17 15:37
 */
@Configuration
//扫描生产者service
@DubboComponentScan(basePackages = "com.ler.dubbo.demo.service.impl")
public class DubboConfiguration {

	/**
	 * 当前应用配置
	 */
	@Bean
	public ApplicationConfig applicationConfig() {
		ApplicationConfig applicationConfig = new ApplicationConfig();
		//应用名字
		applicationConfig.setName("dubbo-demo");
		Map<String, String> parameters = new HashMap<>(16);
		//qos打开,一台机上多个项目时,可能会造成端口冲突
		parameters.put("qos.enable", "false");
		applicationConfig.setParameters(parameters);
		return applicationConfig;
	}

	/**
	 * 连接注册中心配置
	 */
	@Bean
	public RegistryConfig registryConfig() {
		RegistryConfig registryConfig = new RegistryConfig();
		//协议
		registryConfig.setProtocol("zookeeper");
		//zk地址
		registryConfig.setAddress("127.0.0.1:2181");
		//缓存存放路径
		registryConfig.setFile("dubbo.cache");
		//whether to export service on the register center
		registryConfig.setRegister(true);
		registryConfig.setClient("curator");
		return registryConfig;
	}

	/**
	 * 服务提供者协议配置
	 */
	@Bean
	public ProtocolConfig protocolConfig() {
		ProtocolConfig protocolConfig = new ProtocolConfig();
		//协议名字 还有其他的,感兴趣的可以去搜一下看看 rmi协议,hessian协议,thrift协议,http协议
		protocolConfig.setName("dubbo");
		//service port,-1 随机端口
		protocolConfig.setPort(-1);
		//thread pool size (fixed size)
		protocolConfig.setThreads(100);
		return protocolConfig;
	}

	/**
	 * 消费者统一设置
	 */
	@Bean
	public ConsumerConfig consumerConfig() {
		ConsumerConfig consumerConfig = new ConsumerConfig();
		//超时时间
		consumerConfig.setTimeout(3000);
		//启动检查
		consumerConfig.setCheck(false);
		//懒加载
		consumerConfig.setLazy(true);
		return consumerConfig;
	}
}

生产者

  • Domain
package com.ler.dubbo.api.domain;

import java.io.Serializable;
import lombok.Data;

/**
 * @author lww
 * @date 2019-08-17 15:42
 */
@Data
public class User implements Serializable {

	private static final long serialVersionUID = 1L;

	private String name;

	private Integer age;
	
}
  • Service
package com.ler.dubbo.api.service;

import com.ler.dubbo.api.domain.User;

/**
 * @author lww
 * @date 2019-08-17 15:41
 */
public interface UserService {


	User getUser();
}

  • ServiceImpl
package com.ler.dubbo.demo.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.ler.dubbo.api.domain.User;
import com.ler.dubbo.api.service.UserService;

/**
 * @author lww
 * @date 2019-08-17 15:53
 */
 //Dubbo的Service注解,此处的timeout优先级更高
@Service(timeout = 5000)
//@Component 可以使用Spring的@Component注解,来让Spring来管理。因为测试Dubbo不用这个注解
public class UserServiceImpl implements UserService {

	@Override
	public User getUser() {
		User user = new User();
		user.setName("Hello Dubbo!");
		user.setAge(123);
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return user;
	}

}

消费者

  • Service
package com.ler.dubbo.demo.service;

import com.ler.dubbo.api.domain.User;

public interface LocalUserService {

	User getUser();
}
  • ServiceImpl
package com.ler.dubbo.demo.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.ler.dubbo.api.domain.User;
import com.ler.dubbo.api.service.UserService;
import com.ler.dubbo.demo.service.LocalUserService;
import org.springframework.stereotype.Service;

/**
* @author lww
* @date 2019-08-17 16:53
*/
//Spring的Service注解
@Service 
public class LocalUserServiceImpl implements LocalUserService {

   //dubbo注解
   @Reference
   private UserService userService;

   @Override
   public User getUser() {
   	User user = userService.getUser();
   	return user;
   }
}
  • Controller
package com.ler.dubbo.demo.controller;

import com.ler.dubbo.api.domain.User;
import com.ler.dubbo.demo.result.HttpResult;
import com.ler.dubbo.demo.service.LocalUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author lww
 * @date 2019-08-17 16:55
 */
@Api(value = "/", description = "用户相关")
@RequestMapping("/")
@RestController
public class UserController {

	@Resource
	private LocalUserService localUserService;

	@ApiOperation("获取用户")
	@GetMapping("/user")
	public HttpResult getUser() {
		User user = localUserService.getUser();
		return HttpResult.success(user);
	}
}
  • 超时时间统一设置为3秒,睡眠4秒

    超时

  • 在方法上设置为5秒,修改后要重启,才能看到效果

    在方法上设置为5秒

  • 响应正常

    响应正常

总结

下面是项目代码 项目源码