0. Intro
This is some kind of refreshment of one of my previous posts: "Microservices with spring boot"updates:
- codebase migrated to version of spring boot: 2.1.4
- used"feign client" instead of "rest template" for micro-services interaction
- used "zipkin" and "sleuth.sampler" for application monitoring
I will not be providing a lot of details - they are in my previous post. DRY - don't repeat yourself :)
1. Architecture
Actually, architecture is the same as in previous post. Client is communicating with 3 micro-services:But apart from them, we also have some "infrastructure micro-services":
Next picture is taken from zipkin - to show micro-services communication flow: we're calling edge-server and providing it with details of server we actually want to call. Below, we're calling from edge-server - cart-service(method cart/test), which calling through edge-server user-service 2 times (user/login and user/byToken) and again through edge-server - item-service (item/getAll):
2. Discovery server
The same stuff as in my previous post - I'm using Eureka:3. Micro-services interaction
As I mentioned at the beginning, I'm using "feign client" for micro-services interaction. I'll show it on example of "cart-service" - it should call "user-service" to get user details and also it should get some items details from "item-service".3.1. Properties
file application.properties:spring.application.name=cart-service
server.port=8100
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
- here we're defining "coordinates" of our discovery service to get information about services we may need (user and item services)
file bootstrap.properties:
spring.zipkin.base-url=http://localhost:9411/
spring.sleuth.sampler.probability=1
- here we're defining "coordinates" of zipkin application - we 'll be sending there requests traces.
3.2 Feign clients
In feign clients we're defining our "edge-server". Also we're defining "ribbon-client" for service we want to call - it can be different instances of one service, so ribbon client needed for load-balancing. And finally in methods, we're defining the exact rest-services we want to call.Item service feign client:
package com.demien.sprcloud.cartservice.controller;
import java.util.List; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.demien.sprcloud.cartservice.domain.Item; @FeignClient(contextId = "itemClient", name = "edge-server") @RibbonClient(name = "item-service") public interface ItemServiceProxy { @RequestMapping(value = "/item-service/item/{itemId}", method = RequestMethod.GET) public Item getById(@PathVariable("itemId") String itemId); @RequestMapping(value = "/item-service/item/getAll", method = RequestMethod.GET) public List<Item> getAll(); }
User service feign client:
package com.demien.sprcloud.cartservice.controller; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(contextId = "userClient", name = "edge-server") @RibbonClient(name = "user-service") public interface UserServiceProxy { @RequestMapping(value = "/user-service/user/login", method = RequestMethod.POST) public String login(@RequestParam("userId") String userId, @RequestParam("userPassword") String userPassword); @RequestMapping(value = "/user-service/user/byToken/{tokenId}", method = RequestMethod.GET) public String userByToken(@PathVariable("tokenId") String tokenId); }
3.3. Test method with interaction
Next method is just for emulation of some process where user is logging in, adding some items into cart: our cart-service will be communicating with item and user services. Now we can "autowire" our feign clients - and just call them! Lines with calls - are in bold.@Autowired private UserServiceProxy userServiceProxy; @Autowired private ItemServiceProxy itemServiceProxy; public String getDefaultResponse() { return "Something is wrong. Please try again later"; } @HystrixCommand(fallbackMethod = "getDefaultResponse") @RequestMapping(method = RequestMethod.GET, value = "/test") public String test() { final StringBuilder result = new StringBuilder(); result.append("Logging in into userService as user1/pasword <br/> "); final String tokenId = this.userServiceProxy.login("user1", "password1"); result.append("Received Token: " + tokenId + "<br/><br/>"); result.append("Getting user details from userService by token <br/>"); final String userDetails = this.userServiceProxy.userByToken(tokenId); result.append("Reseived UserDetails: " + userDetails + "<br/><br/>"); result.append("Getting item list from itmService <br/>"); final List<Item> items = this.itemServiceProxy.getAll(); result.append("Reseived items: <br/>"); items.forEach(item -> result.append(" " + item.toString() + " <br/>")); return result.toString(); }
Now to test it we can open in browser URL: http://localhost:8765/cart-service/cart/test
and result should be:
Logging in into userService as user1/pasword
Received Token: ec1a5d78-a8c5-4392-90bb-cbca7d8c9244
Getting user details from userService by token
Reseived UserDetails: {"id":"user1","name":"First User","address":"First Address"}
Getting item list from itmService
Reseived items:
Item(itemId=I6S, itemName=IphoNovatekne 6s, price=400.00)
Item(itemId=I7, itemName=Iphone 7, price=500.00)
Item(itemId=N5, itemName=Samsung galaxy note 5, price=450.00)
- so we successfully called 2 micro-services!
4. Zipkin
Zipkin lives here. It's a distributing trace system. To use it I just downloaded JAR file and started it by "java -jar zipkinFileName.jar"My micro-services are already configured for using trace information to zipkin (bootstrap.propeties at #3.1). So when zipking is started it's possible to monitor them:
Now we can drill-down to details and found the picture I shown at the beginning:
I think this picture makes much more sense now - it's a "map" of execution of my test rest service from #3.3.
No comments:
Post a Comment