Microservices Notes
Microservices Notes
Advantages
1) Development is easy
2) Deployment is easy
3) Performance
4) Easy Testing
5) Easy Debugging
6) KT is easy
1) Dis-Advantages
1) Single point of failure
2) Whole Application Re-Deployment
3) Scalability ( Increasing & Decreasing resources based on demand )
4) Reliability (Strong)
5) Availability (Zero Downtime)
1. If we develop the functionalities in multiple services/apis then it is called as Microservices Architecture
Based Application.
2. Every Microservice will have its own goal
Advantages
1) Loosely coupled
2) Fast Development
3) Quick Releases
4) Flexibility
5) Scalability
6) No Single Point of failure
7) Technology independence
Challenges
1) Bounded context (identifying no.of services to develop)
2) Lot of configurations
3) Visibility
4) Testing is difficult
5) Debugging
Microservices Architecture
1. Microservices is an architectural design pattern to develop our applications
2. There is no fixed architecture for Microservices Based Applications
3. People are customizing Microservices Architecture according to their requirement
URL : http://localhost:port/
Step-3) Download & Run Zipkin Server
1) Download zipkin jar from below URL
URL : https://search.maven.org/remote_content?g=io.zipkin&a=zipkin-server&v=LATEST&c=exec
2) Run the zipkin server jar file using below command
$ java -jar <zipkin-server-jar>
Step-4) Develop REST API (WELCOME API)
@Component
public class MyPreFilter implements GlobalFilter {
Logger logger = LoggerFactory.getLogger(MyPreFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
logger.info("filter() method executed....");
// Access request information
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
Set<String> keySet = headers.keySet();
keySet.forEach(key -> {
List<String> values = headers.get(key);
System.out.println(key + "::" + values);
});
return chain.filter(exchange);
}
}
When we send request to REST API using POSTMAN, it will send POSTMAN Token in reuqest header.
Using this token we can differentiate request came from other apps or from POSTMAN.
Load Balancing
1) If we run our application on Single Server then all requests will be sent to single server
2) Burden will be increased on the server
3) When burden got increased request processing gets delayed
4) Sometimes our server might crash due to heavy load
To overcome above problems we will use Load Balancing concept
Load Balancing is the process of distributing load to multiple servers
LBR implementation in Mini Project
Make below changes in WelcomeApi Rest Controller
@RestController
public class WelcomeRestController {
@Autowired
private Environment env;
@GetMapping("/welcome")
public String welcomeMsg() {
String port = env.getProperty("server.port");
String msg = "Welcome to Ashok IT..!!" + " (Port :: " + port + ")";
return msg;
}
}
Run Welcome API with 3 instances
-> Righ Click on API
-> Run As -> Run Configurations
-> Select Application
-> Arguments
-> VM Arguments (-Dserver.port=8082)
-> Apply & Run it
Check Eureka Dashboard
What is Cache ?
1) Cache is a temporary storage
2) When our application wants to access same data frequently then we will use Cache memory
3) Cache will improve performance of our application by reducing database calls
4) Note: Database calls are always costly which will take more time to execute
5) To reduce no.of round trips between application and database we will use 'Cache'
Redis Cache
1) Redis is one of the distributed cache available in the market
2) Redis will store data in key-value pair
3) Multiple Applications can connect with Redis Cache at a time...
4) The open source, in-memory data store used by millions of developers as a database, cache, streaming
engine, and message broker.
Redis Setup
1) Download Redis Software
2) URL : https://redis.io/download/#redis-downloads
3) Run 'redis-server.exe' file
4) Note: By default it runs on '6379' port number
5) Run 'Redis-cli.exe' file
6) Type 'ping' command in Redis CLI
7) Note: Server willl repond with 'PONG' as response
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
@Configuration
public class RedisConfig {
@Bean
public JedisConnectionFactory getJedisConnection() {
JedisConnectionFactory factory = new JedisConnectionFactory();
// factory.setHostName(hostName);
// factory.setPassword(password);
// factory.setPort(port);;
return factory;
}
@Bean
@Primary
public RedisTemplate<String, User> getRedisTemplate(JedisConnectionFactory factory) {
RedisTemplate<String, User> rt = new RedisTemplate<>();
rt.setConnectionFactory(factory);
return rt;
}
}
package in.ashokit.binding;
import java.io.Serializable;
import lombok.Data;
@Data
public class User implements Serializable{
private Integer uid;
private String name;
private Integer age;
}
@RestController
public class UserRestController {
private HashOperations<String, Integer, User> hashOps;
public UserRestController(RedisTemplate<String, User> redisTemplate) {
hashOps = redisTemplate.opsForHash();
}
@PostMapping("/user")
public String storeData(@RequestBody User user) {
hashOps.put("PERSONS", user.getUid(), user);
return "success";
}
@GetMapping("/user/{uid}")
public User getData(@PathVariable Integer uid) {
User value = (User) hashOps.get("PERSONS", uid);
return value;
}
@GetMapping("/users")
public List<User> getAllUsers(){
return hashOps.values("PERSONS");
}
@DeleteMapping("/user/{uid}")
public String deleteUser(@PathVariable Integer uid) {
hashOps.delete("PERSONS", uid);
return "User Deleted";
}
}
Actuator Endpoints
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
shutdown:
enabled: true
@RestController
public class WelcomeRestController {
@Value("${messages.welcome}")
private String welcomeMsg;
@Value("${messages.greet}")
private String greetMsg;
@GetMapping("/welcome")
public String welcomeMsg() {
return welcomeMsg;
}
@GetMapping("/greet")
public String greetMsg() {
return greetMsg;
}
}
application messages and REST ENdpoint URLS are not recommended to hardcode in java classes.
Because if we change any message or any url then we have to compile and package entire application.
To avoid this problem we will configure messages and URLs in application.properties file or in
application.yml file
When we change application.properties file or application.yml file we no need to compile and build
entire project .
1) Create Git Hub Repository and keep configuration properties in git hub repo
Note: We need use application name for configuration properties/yml file name
Ex:
welcome.yml
welcome-dev.yml
welcome-prod.yml
admin.yml
admin-dev.yml
admin-prod.yml
reports.yml
reports-dev.yml
reports-prod.yml
Microservice To Load Config Properties using Config Server (Config Client App)
1) Create Boot application with below dependencies
a) config-client
b) web-starter
c) cloud-bootstrap
2) Configure application name, application port, config-server-url, profile
a) bootstrap.yml (app-name & config-server-url)
spring:
application:
name: welcome
cloud:
config:
uri: http://localhost:8080
b) application.yml (server port)
server:
port: 9090
3) Create Rest Controller with required methods
@RestController
@RefreshScope
public class WelcomeRestController {
@Value("${msg:Config Server Not Working}")
private String msg;
@GetMapping("/")
public String getWelcomeMsg() {
return msg;
}
}
4) Run the application and test it.
}
@RestController
public class DemoRestController {
private Logger logger = LoggerFactory.getLogger(DemoRestController.class);
@GetMapping("/")
public String doAction() {
String msg = "Action in progress";
try {
int i = 10 / 0;
} catch (Exception e) {
logger.error("Exception Occured ::" + e, e);
throw new ArithmeticException(e.getMessage());
}
return msg;
}
@ExceptionHandler(value=ArithmeticException.class)
public ResponseEntity<ExceptionInfo> handleAE(ArithmeticException ae) {
ExceptionInfo exception = new ExceptionInfo();
exception.setMsg(ae.getMessage());
exception.setCode("AIT0004");
return new ResponseEntity<>(exception, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Spring Security
1) To implement security for our applications Spring provided 'security' module
2) To use Spring Security in our project 'spring-security-starter' we need to add in pom.xml file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3) By default it will secure all the endpoints of our application
Default uname : user
Default Pwd: Will be printed on the console
4) To override default credentials we can configure credentails in application.properties file
spring.security.user.name=admin
spring.security.user.password=admin@123
--------------------------------
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CustomerEvent {
private String name;
private Date createDate;
}
---------------------------------
@RestController
public class CustomerRestController {
@GetMapping(value = "/event", produces = "application/json")
public ResponseEntity<Mono<CustomerEvent>> getEvent() {
CustomerEvent event = new CustomerEvent("Ashok", new Date());
Mono<CustomerEvent> customerMono = Mono.just(event);
return new ResponseEntity<Mono<CustomerEvent>>(customerMono, HttpStatus.OK);
}
@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public ResponseEntity<Flux<CustomerEvent>> getEvents() {
// creating binding object with data
CustomerEvent event = new CustomerEvent("Ashok", new Date());
// creating stream for binding object
Stream<CustomerEvent> customerStream = Stream.generate(() -> event);
// create flux object using stream
Flux<CustomerEvent> cflux = Flux.fromStream(customerStream);
// setting response interval
Flux<Long> intervalFlux = Flux.interval(Duration.ofSeconds(5));
// combine interval flux and customer event flux
Flux<Tuple2<Long, CustomerEvent>> zip = Flux.zip(intervalFlux, cflux);
// Getting Tuple value as T2
Flux<CustomerEvent> fluxMap = zip.map(Tuple2::getT2);
//sending response
return new ResponseEntity<>(fluxMap, HttpStatus.OK);
}
}
1) Component
2) Metadata
3) Template
4) Data Binding
5) Module
6) Service
7) Dependency Injection
8) Directive
9) Pipes
10) Angular application is collection of components. In components we will write logic to send data to
template and capture data from template. Components are TypeScript classes.
11) Metadata nothing data about the data. It provides information about components.
12) Template is a view where we will write our presentation logic. In Angular application template is a HTML
file. Every Component contains its own Template.
13) Data Binding is the process of binding data between component property and view element in template
file.
14) Module is a collection of components directives and pipes
15) Service means it contains re-usable business logic. Service classes we will inject in Components using
Depdency Injection.
16) Dependency Injection is the process of injecting dependent object into target object. In Angular
applications services will be injected into components using DI.
17) Directives are used to manipulate DOM elements.
18) Pipes are used to transform the data before displaying
1) Note: We are done with angular setup... lets start building angular applications What is Unit testing ?
2) It is the process of testing unit amount of work
3) When we implement code, we need to test weather that code is working or not
4) With the help of unit testing we can identify issues in the code
5) To perform Unit testing we will use Junit
6) Junit is an open source & free framework to perform unit testing for java applications
Mocking
1) Mocking is the process of creating substitute object for the real object
2) Using Mock Objects we can perform isolated unit testing
@Service
public class WelcomeService {
public String getMsg() {
String msg = "Good Morning";
return msg;
}
}
-----------------------------------------------------------
@RestController
public class WelcomeRestController {
@Autowired
private WelcomeService service;
@GetMapping("/welcome")
public String welcomeMsg() {
String msg = service.getMsg();
return msg;
}
}
@WebMvcTest(value = WelcomeRestController.class)
public class WelcomeRestControllerTest {
@MockBean
private WelcomeService service;
@Autowired
private MockMvc mockMvc;
@Test
public void welcomeMsgTest() throws Exception {
// defining mock obj behaviour
when(service.getMsg()).thenReturn("Welcome to Ashok IT");
// preparing request
MockHttpServletRequestBuilder reqBuilder = MockMvcRequestBuilders.get("/welcome");
// sending request
MvcResult mvcResult = mockMvc.perform(reqBuilder).andReturn();
// get the response
MockHttpServletResponse response = mvcResult.getResponse();
// validate response status code
int status = response.getStatus();
assertEquals(200, status);
}
}