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

feat: support use database as a registry #4595

Merged
merged 34 commits into from
Oct 23, 2022
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a9e0e3c
feat: support use database as a registry
Anilople Oct 2, 2022
46df1c0
fix: test fail when missing bean RegistryService
Anilople Oct 2, 2022
4a06884
Delete RegistryController.java
Anilople Oct 10, 2022
5615639
feat: add spring.cloud.discovery.enabled=false
Anilople Oct 10, 2022
c84a4b5
refactor: healthCheckInterval -> healthCheckIntervalInSecond
Anilople Oct 10, 2022
aa61c4c
fix: 'com.ctrip.framework.apollo.biz.repository.RegistryRepository' t…
Anilople Oct 10, 2022
c2be03d
refactor: Registry -> ServiceRegistry. change all config prefix to ap…
Anilople Oct 10, 2022
343d9f9
feat: add service registry config heartbeatIntervalInSecond
Anilople Oct 10, 2022
1eed34a
feat: clear service instances 1 days ago
Anilople Oct 10, 2022
e4513c6
fix: move '@Transactional' from repository up to service
Anilople Oct 10, 2022
4fa67b7
refactor: Change all to use jvm `LocalDateTime.now()`
Anilople Oct 10, 2022
bcc5575
fix test fail
Anilople Oct 10, 2022
98b55f7
Update apolloconfigdb.sql
Anilople Oct 10, 2022
e6de6ae
refactor: split heartbeat and deregister
Anilople Oct 10, 2022
a1c1488
fix: catch Throwable instead of catch Exception
Anilople Oct 14, 2022
ef4fc4b
refactor: use stream and lambda instead of for each loop filter
Anilople Oct 14, 2022
fa0d4f7
delete USING BTREE
Anilople Oct 14, 2022
fbf7d2d
fix: label -> cluster
Anilople Oct 14, 2022
5d57924
Update scripts/sql/apolloconfigdb.sql
Anilople Oct 14, 2022
5bb73d1
Update scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql
Anilople Oct 14, 2022
16f237d
test: add bean exist check
Anilople Oct 14, 2022
a9a05b9
feat: add Metadata column
Anilople Oct 14, 2022
c61f8ef
refactor: only use cluster in DatabaseDiscoveryClientImpl
Anilople Oct 14, 2022
ad2a1f0
feat: add metadata config in code
Anilople Oct 14, 2022
4cb1443
Merge branch 'master' into feature/register-to-database
Anilople Oct 14, 2022
c358128
Merge branch 'master' into feature/register-to-database
Anilople Oct 17, 2022
6fa748f
test: add tests of registry
Anilople Oct 17, 2022
b4fc7f0
Merge branch 'master' into feature/register-to-database
Anilople Oct 20, 2022
9219f34
docs: Enable database-discovery to replace built-in eureka
Anilople Oct 20, 2022
1baec92
Update CHANGES.md
Anilople Oct 20, 2022
4c3e409
room -> cluster
Anilople Oct 22, 2022
8eea742
room -> cluster
Anilople Oct 22, 2022
02370fa
feat: when database fail, database-discovery still be useful. by deco…
Anilople Oct 23, 2022
1d1d77e
test: fix when DatabaseDiscoveryClient wrap by decorator
Anilople Oct 23, 2022
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Copyright 2022 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.
#
eureka.client.enabled=false
Anilople marked this conversation as resolved.
Show resolved Hide resolved
spring.cloud.discovery.enabled=false

apollo.service.registry.enabled=true
apollo.service.registry.cluster=default
apollo.service.registry.heartbeatIntervalInSecond=10

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2022 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.biz.entity;

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
class JpaMapFieldJsonConverter implements AttributeConverter<Map<String, String>, String> {

private static final Gson GSON = new Gson();

private static final TypeToken<HashMap<String, String>> TYPE_TOKEN = new TypeToken<HashMap<String, String>>() {
};

@SuppressWarnings("unchecked")
private static final Type TYPE = TYPE_TOKEN.getType();

@Override
public String convertToDatabaseColumn(Map<String, String> attribute) {
return GSON.toJson(attribute);
}

@Override
public Map<String, String> convertToEntityAttribute(String dbData) {
return GSON.fromJson(dbData, TYPE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright 2022 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.biz.entity;

import com.ctrip.framework.apollo.biz.registry.ServiceInstance;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PrePersist;
import javax.persistence.Table;

/**
* use database as a registry instead of eureka, zookeeper, consul etc.
* <p>
* persist {@link ServiceInstance}
*/
@Entity
@Table(name = "ServiceRegistry")
public class ServiceRegistry {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Id")
private long id;

@Column(name = "ServiceName", nullable = false)
private String serviceName;

/**
* @see ServiceInstance#getUri()
*/
@Column(name = "Uri", nullable = false)
private String uri;

/**
* @see ServiceInstance#getCluster()
*/
@Column(name = "Cluster", nullable = false)
private String cluster;

@Column(name = "Metadata", nullable = false)
@Convert(converter = JpaMapFieldJsonConverter.class)
private Map<String, String> metadata;

@Column(name = "DataChange_CreatedTime", nullable = false)
private LocalDateTime dataChangeCreatedTime;

/**
* modify by heartbeat
*/
@Column(name = "DataChange_LastTime", nullable = false)
private LocalDateTime dataChangeLastModifiedTime;

@PrePersist
protected void prePersist() {
if (this.dataChangeCreatedTime == null) {
dataChangeCreatedTime = LocalDateTime.now();
}
if (this.dataChangeLastModifiedTime == null) {
dataChangeLastModifiedTime = dataChangeCreatedTime;
}
}

@Override
public String toString() {
return "Registry{" +
"id=" + id +
", serviceName='" + serviceName + '\'' +
", uri='" + uri + '\'' +
", cluster='" + cluster + '\'' +
", metadata='" + metadata + '\'' +
", dataChangeCreatedTime=" + dataChangeCreatedTime +
", dataChangeLastModifiedTime=" + dataChangeLastModifiedTime +
'}';
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getServiceName() {
return serviceName;
}

public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}

public String getUri() {
return uri;
}

public void setUri(String uri) {
this.uri = uri;
}

public String getCluster() {
return cluster;
}

public void setCluster(String cluster) {
this.cluster = cluster;
}

public Map<String, String> getMetadata() {
return metadata;
}

public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}

public LocalDateTime getDataChangeCreatedTime() {
return dataChangeCreatedTime;
}

public void setDataChangeCreatedTime(LocalDateTime dataChangeCreatedTime) {
this.dataChangeCreatedTime = dataChangeCreatedTime;
}

public LocalDateTime getDataChangeLastModifiedTime() {
return dataChangeLastModifiedTime;
}

public void setDataChangeLastModifiedTime(LocalDateTime dataChangeLastModifiedTime) {
this.dataChangeLastModifiedTime = dataChangeLastModifiedTime;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2022 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.biz.registry;

import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties;
import java.util.List;

/**
* @see org.springframework.cloud.client.discovery.DiscoveryClient
*/
public interface DatabaseDiscoveryClient {

/**
* find by {@link ApolloServiceRegistryProperties#getServiceName()},
* then filter by {@link ApolloServiceRegistryProperties#getCluster()}
*/
List<ServiceInstance> getInstances(String serviceName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2022 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.biz.registry;

import com.ctrip.framework.apollo.biz.entity.ServiceRegistry;
import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties;
import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties;
import com.ctrip.framework.apollo.biz.service.ServiceRegistryService;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class DatabaseDiscoveryClientImpl implements DatabaseDiscoveryClient {
private final ServiceRegistryService serviceRegistryService;

private final ApolloServiceDiscoveryProperties discoveryProperties;

private final String cluster;

public DatabaseDiscoveryClientImpl(
ServiceRegistryService serviceRegistryService,
ApolloServiceDiscoveryProperties discoveryProperties,
String cluster) {
this.serviceRegistryService = serviceRegistryService;
this.discoveryProperties = discoveryProperties;
this.cluster = cluster;
}

/**
* find by {@link ApolloServiceRegistryProperties#getServiceName()}
*/
@Override
public List<ServiceInstance> getInstances(String serviceName) {
final List<ServiceRegistry> serviceRegistryListFiltered;
{
LocalDateTime healthTime = LocalDateTime.now()
.minusSeconds(this.discoveryProperties.getHealthCheckIntervalInSecond());
List<ServiceRegistry> filterByHealthCheck =
this.serviceRegistryService.findByServiceNameDataChangeLastModifiedTimeGreaterThan(
serviceName, healthTime
);
serviceRegistryListFiltered = filterByCluster(filterByHealthCheck, this.cluster);
}

return serviceRegistryListFiltered.stream()
.map(DatabaseDiscoveryClientImpl::convert)
.collect(Collectors.toList());
}

static ApolloServiceRegistryProperties convert(ServiceRegistry serviceRegistry) {
ApolloServiceRegistryProperties registration = new ApolloServiceRegistryProperties();
registration.setServiceName(serviceRegistry.getServiceName());
registration.setUri(serviceRegistry.getUri());
registration.setCluster(serviceRegistry.getCluster());
return registration;
}

static List<ServiceRegistry> filterByCluster(List<ServiceRegistry> list, String cluster) {
return list.stream()
.filter(serviceRegistry -> Objects.equals(cluster, serviceRegistry.getCluster()))
.collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2022 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.biz.registry;

/**
* @see org.springframework.cloud.client.serviceregistry.ServiceRegistry
*/
public interface DatabaseServiceRegistry {

/**
* register an instance to database
*/
void register(ServiceInstance instance);

/**
* remove an instance from database
*/
void deregister(ServiceInstance instance);
}
Loading