返回介绍

8.3 使用动态路由和断路器

发布于 2025-04-26 13:26:35 字数 7595 浏览 0 评论 0 收藏 0

8.2 节创建了一个发现服务器,并向其注册了几个微服务(客户端),这一节将介绍如何在这些服务之间,使用动态路由、断路器和故障容错等功能。

当客户端发现服务器注册之后,客户端之间就可以通过 Zuul 路由代理协议,使用应用的名称来访问各自的 REST 资源。

8.3.1 依赖配置

要启用动态路由、断路器和服务监控等功能,首先需要在各个客户端的工程中引用如代码清单 8-14 所示的 Maven 依赖配置。

代码清单 8-14 启用路由和断路器等的依赖配置

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
        <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

其次在各个使用上述功能的工程的主程序中,增加如下注解,即可启用路由代理服务和启用监控服务功能。

@EnableZuulProxy
@EnableHystrix

8.3.2 共享 REST 资源

在实例工程的 data 模块,使用 Neo4j 图形数据库,创建了三个节点,分别是单位、用户、角色,并创建了两个关系,即用户隶属于单位的关系和用户拥有角色的关系。有关节点和关系的实体建模如表 8-3 所示。

表 8-3 实体建模列表

节点和关系实体的持久化,可以使用资源库的方式实现。代码清单 8-15 是用户节点的持久化实现,并且在实现持久化的同时也共享了 REST 资源。其中注解 @Reposit-oryRestResource 标注这个接口不但是一个数据库的资源库,也是一个 REST 资源共享,并把资源的名称和路径定义为 users。将在下一小节中介绍如何使用这个 REST 的资源共享。

代码清单 8-15 用户节点的 REST 资源库

@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends GraphRepository<User> {
    User findByName(@Param("name") String name);
    @Query("MATCH (u:User) WHERE u.name =~ ('(?i).*'+{name}+'.*') RETURN u")
    Collection<User> findByNameContaining(@Param("name") String name);
}

现在可以使用如代码清单 8-16 所示的测试程序来为 Neo4j 数据库生成一些测试数据,以方便后面的测试。测试程序首先清空数据库的记录(如果存在的话),然后创建一个单位命名为“开发部”,创建两个角色分别是 admin 和 manage,创建一个用户,用户名为 user,将用户“安排”到单位“开发部”中,并给它“分配”两个角色为 admin 和 manage。

代码清单 8-16 Neo4j 测试程序

@Autowired
UnitRepository unitRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
UserRepository userRepository;
@Test
public void initData() {
    userRepository.deleteAll();
    roleRepository.deleteAll();
    unitRepository.deleteAll();
    Unit unit = new Unit();
    unit.setName("开发部




");
    unit.setCreate(new Date());
    unitRepository.save(unit);
    Assert.notNull(unit.getId());
    Role role = new Role();
    role.setName("admin");
    role.setCreate(new Date());
    roleRepository.save(role);
    Assert.notNull(role.getId());
    Role role1 = new Role();
    role1.setName("manage");
    role1.setCreate(new Date());
    roleRepository.save(role1);
    Assert.notNull(role1.getId());
    User user = new User();
    user.setName("user");
    user.setSex(1);
    user.setEmail("user@email.com");
    user.setCreate(new Date());
    user.beBelong(unit,"安排




");
    user.addOwner(role, "分配




");
    user.addOwner(role1, "分配




");
    userRepository.save(user);
    Assert.notNull(user.getId());
}

运行测试程序,可以生成一些测试数据。数据生成后,启动 data 模块,然后在浏览器中输入网址: http://localhost:9000/users

现在可以看到如图 8-3 所示的资源数据,从图中可以看出,可以使用下列链接来访问这些资源数据。

http://localhost:9000/users/132
http://localhost:9000/users/search/findByName?name=user……





图 8-3 节点实体 User 的 REST 资源

如果这时启动 web 模块,然后使用链接 http://localhost:9001/data/users ,同样可以看到类似图 8-3 所示的样子,只不过这时是在 web 模块打开的链接,而不是 data 模块,如图 8-4 所示。也就是说,可以在 web 模块中,像使用本地数据一样使用 data 模块的数据。

图 8-4 在 web 模块中查询的节点实体 User 的 REST 资源

8.3.3 通过路由访问 REST 资源

可以使用下面几种方法通过 Zuul 路由代理方式来访问不同服务中的 REST 资源。

- JavaScript;

- RestTemplate;

- FeignClient。

代码清单 8-17 是在 web 模块中,使用 data 模块中的 REST 资源数据的一个 jQuery 例子,即将用户名称作为参数,调用 data 模块的 findByNameContaining 使用模糊查询的方法,返回符合条件的用户列表。

代码清单 8-17 使用 jQuery 调用 REST 资源的例子

var pageaction = function(){
    $.get('/data/users/search/findByNameContaining?name='+$("#name").val(),
        function(data){
        var currentData = data["_embedded"].users;
        fillData(currentData);
    });
}

代码清单 8-18 是使用 RestTemplate 的一个例子,即同样使用用户名称作为参数,调用 data 模块的 findByName 方法,返回一个用户对象。

代码清单 8-18 使用 RestTemplate 调用 REST 资源的实例

@Service
public class UserService {
        @Autowired
        RestTemplate restTemplate;
        public User getUserByName(String name) {
            Map<String, Object> params = new HashMap<>();
            params.put("name", name);
            User user = restTemplate.getForObject("http://data/users/search/find-ByName?name={name}", User.class, params);
            return user;
        }
}

代码清单 8-19 是使用 FeignClient 的一个例子,它使用注解 @FeignClient("data")的方式,创建一个接口,调用 data 模块中的 findById 方法。

代码清单 8-19 使用 FeignClient 调用 REST 资源的实例

@FeignClient("data")
public interface UserClient {
    @RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
    User findById(@RequestParam("id") Long id);
}

上面各种调用方式,可以按照程序设计的要求选择使用。要使用 FeignClient,还必须在工程的 Maven 依赖中增加“spring-cloud-starter-feign”依赖,并在工程的主程序中增加一个注解:@EnableFeignClients,以启用 FeignClient 的功能。

8.3.4 使用断路器功能

断路器是微服务中的一个故障容错的线路保护开关。如同电路中的负载保护开关一样,断路器将在所调用的服务过载或出现故障时,自动阻断对服务的访问和调用,转而调用备用方法。

当一个系统服务突然出现故障或超载时,后面访问将会陷入无限地延迟和等待的状态之中,由于请求得不到及时响应,访问者可能会因此而不断发送请求,这将造成严重的恶性循环,最终导致整个系统陷入瘫痪状态,甚至会完全崩溃。使用断路器可以避免这种情况发生,起到防患于未然的作用。

代码清单 8-20 是一个使用断路器和故障容错功能的实例。注解 @HystrixCommand 为 getUserByName 方法配备一个备用方法:getUserFallback。由 getUserFallback 的实现代码可知,该方法只构造了一些虚假数据,以便及时返回请求结果。

代码清单 8-20 使用断路器的实例

@Service
public class UserService {
    @Autowired @LoadBalanced
    RestTemplate restTemplate;
    @HystrixCommand(fallbackMethod = "getUserFallback")
    public User getUserByName(String name) {
        Map<String, Object> params = new HashMap<>();
        params.put("name", name);
        User user = restTemplate.getForObject("http://data/users/search/findBy
Name?name={name}", User.class, params);
        return user;
    }
    private User getUserFallback(String name) {
        User user = new User();
        user.setName(name + " not find");
        user.setEmail("user email");
        Belong belong = new Belong();
        Unit unit = new Unit();
        unit.setName("unit name");
        belong.setUnit(unit);
        user.setBelong(belong);
        Owner owner = new Owner();
        Role role = new Role();
        role.setName("role name");
        owner.setRole(role);
        List<Owner> owners = new ArrayList<>();
        owners.add(owner);
        user.setOwners(owners);
        return user;
    }
}

8.3.5 路由器和断路器测试

现在可以测试路由器和断路器的功能,首先启动实例工程的 discovery 模块,然后启动实例工程的 data 模块和 web 模块,在浏览器中输入网址 http://localhost:9001/

返回一个用户列表的界面,这是在 web 服务中请求了 data 服务,并从中取得用户列表数据的结果。在界面中,单击查看,将向 data 服务请求这个用户的详细资料,如果正常,就打开用户的详细信息界面。图 8-5 是一个正常状态的用户信息查看界面。

图 8-5 服务正常时查看用户信息的界面

如果这时制造人为的故障,直接关闭 data 服务。现在再在界面中单击查看,它不会陷入无限的等待之中,而是立刻就返回了,只是界面上的用户信息是我们上面编写的一些虚假数据,如图 8-6 所示。因为 data 服务出现了故障,所以对 data 服务的请求就触发了断路器的熔断机制。

图 8-6 服务故障时查看用户信息的界面

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。