Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add zookeeper service discovery support(#3557) #4119

Merged
merged 9 commits into from
Dec 21, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions apollo-adminservice/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,16 @@
</dependency>
</dependencies>
</profile>
<profile>
<id>zookeeper-discovery</id>
<dependencies>
<!-- zookeeper discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# Copyright 2021 Apollo Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apollo.eureka.server.enabled=false
eureka.client.enabled=false

#zookeeper enabled
spring.cloud.zookeeper.enabled=true
spring.cloud.zookeeper.discovery.enabled=true
spring.cloud.zookeeper.discovery.register=true
spring.cloud.zookeeper.discovery.instance-id=${spring.cloud.client.ip-address}:${server.port}
10 changes: 10 additions & 0 deletions apollo-configservice/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@
</dependency>
</dependencies>
</profile>
<profile>
<id>zookeeper-discovery</id>
<dependencies>
<!-- zookeeper discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
/**
* For non-eureka discovery services such as kubernetes and nacos, there is no eureka home page, so we need to add a default one
*/
@Profile({"kubernetes", "nacos-discovery", "consul-discovery"})
@Profile({"kubernetes", "nacos-discovery", "consul-discovery", "zookeeper-discovery"})
@RestController
public class HomePageController {
private final DiscoveryService discoveryService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
* Default discovery service for Eureka
*/
@Service
@ConditionalOnMissingProfile({"kubernetes", "nacos-discovery", "consul-discovery"})
@ConditionalOnMissingProfile({"kubernetes", "nacos-discovery", "consul-discovery", "zookeeper-discovery"})
public class DefaultDiscoveryService implements DiscoveryService {

private final EurekaClient eurekaClient;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2021 Apollo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.ctrip.framework.apollo.metaservice.service;

import java.util.Collections;
import java.util.List;

import com.ctrip.framework.apollo.core.dto.ServiceDTO;
import com.ctrip.framework.apollo.tracer.Tracer;
import com.google.common.collect.Lists;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
* Service discovery zookeeper implementation
*/
@Service
@Profile({"zookeeper-discovery"})
@ConditionalOnClass(name = {"org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryClient"})
public class ZookeeperDiscoveryService implements DiscoveryService {

private final DiscoveryClient discoveryClient;

public ZookeeperDiscoveryService(DiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}

@Override
public List<ServiceDTO> getServiceInstances(String serviceId) {

if (discoveryClient == null || CollectionUtils.isEmpty(discoveryClient.getInstances(serviceId))) {
Tracer.logEvent("Apollo.Discovery.NotFound", serviceId);
return Collections.emptyList();
}

List<ServiceDTO> serviceDTOList = Lists.newLinkedList();
discoveryClient.getInstances(serviceId).forEach(instance -> {
ServiceDTO serviceDTO = this.toServiceDTO(instance, serviceId);
serviceDTOList.add(serviceDTO);
});

return serviceDTOList;
}

private ServiceDTO toServiceDTO(ServiceInstance instance, String appName) {
ServiceDTO service = new ServiceDTO();
service.setAppName(appName);
service.setInstanceId(instance.getInstanceId());
String homePageUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/";
service.setHomepageUrl(homePageUrl);
return service;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# Copyright 2021 Apollo Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apollo.eureka.server.enabled=false
eureka.client.enabled=false

#zookeeper enabled
spring.cloud.zookeeper.enabled=true
spring.cloud.zookeeper.discovery.enabled=true
spring.cloud.zookeeper.discovery.register=true
spring.cloud.zookeeper.discovery.instance-id=${spring.cloud.client.ip-address}:${server.port}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright 2021 Apollo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.ctrip.framework.apollo.metaservice.service;

import java.util.List;

import com.ctrip.framework.apollo.core.dto.ServiceDTO;
import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class ZookeeperDiscoveryServiceTest {

@Mock
private DiscoveryClient zookeeperDiscoveryClient;

private ZookeeperDiscoveryService zookeeperDiscoveryService;

private String someServiceId;

@Before
public void setUp() throws Exception {
zookeeperDiscoveryService = new ZookeeperDiscoveryService(zookeeperDiscoveryClient);
someServiceId = "someServiceId";
}

@Test
public void testGetServiceInstancesWithEmptyInstances() {
when(zookeeperDiscoveryClient.getInstances(someServiceId)).thenReturn(null);
assertTrue(zookeeperDiscoveryService.getServiceInstances(someServiceId).isEmpty());
}

@Test
public void testGetServiceInstances() {
String someIp = "1.2.3.4";
int somePort = 8080;
String someInstanceId = "someInstanceId";
ServiceInstance someServiceInstance = mockServiceInstance(someInstanceId, someIp, somePort);

when(zookeeperDiscoveryClient.getInstances(someServiceId)).thenReturn(
Lists.newArrayList(someServiceInstance));

List<ServiceDTO> serviceDTOList = zookeeperDiscoveryService.getServiceInstances(someServiceId);
ServiceDTO serviceDTO = serviceDTOList.get(0);
assertEquals(1, serviceDTOList.size());
assertEquals(someServiceId, serviceDTO.getAppName());
assertEquals("http://1.2.3.4:8080/", serviceDTO.getHomepageUrl());

}

private ServiceInstance mockServiceInstance(String instanceId, String ip, int port) {
ServiceInstance serviceInstance = mock(ServiceInstance.class);
when(serviceInstance.getInstanceId()).thenReturn(instanceId);
when(serviceInstance.getHost()).thenReturn(ip);
when(serviceInstance.getPort()).thenReturn(port);

return serviceInstance;
}

}
17 changes: 17 additions & 0 deletions docs/zh/deployment/distributed-deployment-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,23 @@ spring.cloud.consul.host=127.0.0.1
spring.cloud.consul.port=8500
```

##### 2.2.1.2.9 启用外部Zookeeper服务注册中心替换内置eureka
1. 修改build.sh/build.bat,将`config-service`和`admin-service`的maven编译命令更改为
```shell
mvn clean package -Pgithub,zookeeper-discovery -DskipTests -pl apollo-configservice,apollo-adminservice -am -Dapollo_profile=github,zookeeper-discovery -Dspring_datasource_url=$apollo_config_db_url -Dspring_datasource_username=$apollo_config_db_username -Dspring_datasource_password=$apollo_config_db_password
```
2. 分别修改apollo-configservice和apollo-adminservice安装包中config目录下的application-github.properties,配置zookeeper服务器地址
```properties
spring.cloud.zookeeper.connect-string=127.0.0.1:2181
```
3.本地调试
- 修改maven`profiles`项,需要在profiles中将`zookeeper-discovery`项勾选

- 分别修改`apollo-configservice`和`apollo-adminservice`服务对应的`VM options`,激活`zookeeper-discovery`的`profile`
```properties
-Dapollo_profile=github,zookeeper-discovery
```

### 2.2.2 部署Apollo服务端

#### 2.2.2.1 部署apollo-configservice
Expand Down
45 changes: 45 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,51 @@
</dependencies>
</dependencyManagement>
</profile>
<profile>
<id>zookeeper-discovery</id>
<properties>
<apache.curator.version>4.2.0</apache.curator.version>
<apache.zookeeper.version>3.4.14</apache.zookeeper.version>
</properties>
<dependencyManagement>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this dependencyManagement section is not necessary as the zookeeper related dependencies are managed in spring-cloud-zookeeper-dependencies which is imported in spring-cloud-dependencies.

Copy link
Contributor Author

@CalebZYC CalebZYC Dec 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spring-cloud-zookeeper-dependencies用到了curator的依赖,这里引入curator和zookeeper的依赖是考虑到zookeeper版本的兼容性
ZooKeeper Version 3.4.x Compatibility

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. Is there any particular reason that we should stick to the zookeeper 3.4.x version?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the same problem as nobodyiam about introducing zookeeper related dependencies. Also, I found that the current code running on jdk17, zk-client cannot connect to the local zk-server. the exception is as follows.

2021-12-08 17:39:56.700  WARN 61926 --- [localhost:2181)] org.apache.zookeeper.ClientCnxn          : Session 0x0 for server localhost/<unresolved>:2181, unexpected error, closing socket connection and attempting reconnect

java.lang.IllegalArgumentException: Unable to canonicalize address localhost/<unresolved>:2181 because it's not resolvable
	at org.apache.zookeeper.SaslServerPrincipal.getServerPrincipal(SaslServerPrincipal.java:65)
	at org.apache.zookeeper.SaslServerPrincipal.getServerPrincipal(SaslServerPrincipal.java:41)
	at org.apache.zookeeper.ClientCnxn$SendThread.startConnect(ClientCnxn.java:1001)
	at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1060)

When I remove the following dependencies.

		<profile>
			<id>zookeeper-discovery</id>
			<properties>
				<apache.curator.version>4.2.0</apache.curator.version>
				<apache.zookeeper.version>3.4.14</apache.zookeeper.version>
			</properties>
			<dependencyManagement>
				<dependencies>
					<!-- apache curator -->
					<dependency>
						<groupId>org.apache.curator</groupId>
						<artifactId>curator-x-discovery</artifactId>
						<version>${apache.curator.version}</version>
					</dependency>
					<dependency>
						<groupId>org.apache.curator</groupId>
						<artifactId>curator-recipes</artifactId>
						<version>${apache.curator.version}</version>
					</dependency>
					<dependency>
						<groupId>org.apache.curator</groupId>
						<artifactId>curator-framework</artifactId>
						<version>${apache.curator.version}</version>
					</dependency>
					<!-- apache curator end -->
					<!-- zookeeper -->
					<dependency>
						<groupId>org.apache.zookeeper</groupId>
						<artifactId>zookeeper</artifactId>
						<version>${apache.zookeeper.version}</version>
						<exclusions>
							<exclusion>
								<groupId>log4j</groupId>
								<artifactId>log4j</artifactId>
							</exclusion>
							<exclusion>
								<groupId>org.slf4j</groupId>
								<artifactId>slf4j-log4j12</artifactId>
							</exclusion>
						</exclusions>
					</dependency>
					<!-- zookeeper end -->
				</dependencies>
			</dependencyManagement>
		</profile>

Works well on jdk17

<dependencies>
<!-- apache curator -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>${apache.curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${apache.curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${apache.curator.version}</version>
</dependency>
<!-- apache curator end -->
<!-- zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${apache.zookeeper.version}</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- zookeeper end -->
</dependencies>
</dependencyManagement>
</profile>
<profile>
<id>release</id>
<build>
Expand Down