Interview Questions
Self
Introduction
Hi
Name,
Good
Morning!
My
name is Prabhu Prasad, and I am a Tech Lead with over 10 years of
experience in software development. I specialize in designing and developing
robust business applications using Java, SpringBoot Microservices, and REST
APIs. My expertise extends to requirement analaysis, testing, deployment and
leveraging AI tools like GitHub Copiot and LLM.
DSA
I. Data Structures
1.
Arrays
2.
Linked Lists
3.
Stacks
4.
Queues
5.
Maps & Hash Tables
6.
Graphs
7.
Trees
8.
Binary Trees & Binary Search Trees
9.
Self-balancing Trees (AVL Trees, Red-Black Trees, Splay
Trees)
10. Heaps
11. Tries
12. Segment
Trees
13. Fenwick
Trees
14. Disjoint
Set Union
15. Minimum
Spanning Trees
II. Algorithms
16. Divide
and Conquer
17. Sorting
Algorithms (Bubble Sort, Counting Sort, Quick Sort, Merge Sort, Radix Sort)
18. Searching
Algorithms (Linear Search, Binary Search)
·
Hash table internal
·
equals and hashcode
Java 8 features
Streams
Lamda -> anonymous
method->NO name,access modifie, return type
to implment functioninternace
@FunctionalINteface to
avoid to add muiltple mehtods
single abstarct method contains is Finctoin interface.
In addition to single abstract method, we can have
any number of
default & static methods and even public methods
of java.lang.Object class inside a Functional Interface.
Object class methods-> equlas, hashcode, toStirng, wait, notify, notifyall, getClass()
Default and static methods in interface introduced.
default-> to avoid changing all implemented classes if
new functionality added using default method implementation in interface.
Abstract classes
still lambda expressions are not for abstract classes
can create instance variables and create construers and
static and instance blocks but not in interface.
Method reference and lambda
expressions are to implement Functional Interfaces
Method Reference is the process of refering pre-exisng
method using :: reference is called Method reference ex:
System.out::println
Optional
java.Util package
Optional<Object> emptyOptional = Optional.empty()
Optional<String> emailOoptianal =
Optional.of(custome.getEmail());
Optional.ofNullable(customer.getEmail());
It check (if (customer.getEmail==null?empty ():
of(custm.getEmail())));
To get the Otional value use get() method.
If(emailOptiaon.isPresent()){
emialOpgioan.get()
}
emialOptiona.orElse(“default value”)
emailOptional.orElseThrow(()->new
NoSuchElementError(“email not fouldn”))->Supplier Functional interface
emialOptiona.orElseGet(()->“default value”)
filter()->accepts Predicate Function interface
forEach()-> accepts Consumer Functioal interface
->Function Functional Interface.
Memory allocation.
And Permanent Generation-> JVM metadata-. Class
structure,Class metadata and all part of heap memroy and fixed one.
Meta space is out of HEAP and can increase based on
situation. To avoid outofmemeory issues.
==================
Springboot Autocofiguration
Java Desing Patterns
Creational Patterns:
·
Factory, Abstract Factory, Builder, Prototype, Singleton
Structural Patterns:
·
Adapter, Bridge, Composite, Decorator, Facade, Flyweight,
Proxy
Behavioral Patterns:
·
Chain of Responsibility, Command, Interpreter, Iterator,
Mediator, Memento, Observer, State, Strategy, Template Method, Visitor
SOLID Design principles
S -> Single Responsibility Principle
·
Every Java class must have single functionality ex: for
ptinting passbook sepearet class, for loans seperate class, for sending otp
notifications seperate class.
O -> Open & Close Principle
·
Open for extension & Closed for modification
·
Create interface with notification otp an report
·
implement in EmailNOtificatin, Whatsappnotification and
MobileMessageNotification classes and implement Notification interface and its
methods. sendOtp,sendRepots.
L -> Leskov's Substitution Priciple
·
Derived class must be completely substitutable for their
base classes. In other words, if Class A is a subtype
of class B, then we should be able to replace B with A without interrupting
behavior of the program. For this can create multiple interfaces with related
abstract methods and related Calsses can implement only those related interfaces.
so can subclass substitues with baseclass or interface.
·
ex: chat, share phots, video call, publishpost
·
Interface1 chat and share methods
·
Interface2 video call, publishpost
·
Insta class implents both interafaces
·
Whatsapp class implemnts Interface1
·
Facebook class implemts both intrfaces
I -< Interface Segregation Principle
·
Split larger Interface into smaller ones. We should
not force the client to use the methods that they dont want to use.->
similar to single responsibility.
·
ex: UpiPaymentInterace, CashBackInterface
·
Gpay implemtns both-> sendmOny, scarchcard, cashback
·
PhonPe only UpiPaymentsINteraec->No cash back not
forcing. to implment CashBackintefae by splitting it into different interface.
D-> Dependency Inversion Principle
Don't tightly couple with the concrete classes, instead
create interface and make it loosely coupled
ex: public class ShoppingMall{
private Debitcatd debitcatrd;
ShoppingMall(Debitcard debitcare){
this.debitcard = debitcard
} doPurchagetn(debitcard){
creditcard.DoTransaction()
main(){
creaet Debit instance or Creditcard instance and call
doTrancaitno
but when we write intefce and implemnt in Debitcasll and
Creditcat and imoment DoTransactinmethod and in ShoppingMall class invoke what
ever want.
Microservices design patterns
·
Decomposition
·
Strangler
·
API Gateway pattern
Outh2->JWT token
https://www.autodraw.com/share/0NGELIR3UDHB
SpringBootSecurity
Till 2.7
public Class SecurityConfig extends
WebSecurityConfigurerAdapter{
@Override
public void configure(AuthenticationManagerBuilder
auth)thrws Exception{
auth.inMemoryAuthentication()
.withUser()
.password()
.roles();
auth.inMemoryAuthentication()
.withUser()
.password()
.roles();
}
public void configure(HttpSecurity http)thrws
Exception{
http.csrf().disable()
.authoriseRequests().antMatchers("/products/welcome").permitAll()
.and
.authoriseRequests().antMatchers("/products/getAllProducts").authenticated()
.and.httpBasic();
}
Microservices Design pattern
Aggregator pattern
Database per service
Shared database per service
CommandQueryResponsiblitySegregation(CQRS)
Keep Read and Write Opeations(Mircro services in different
or seggregated)
to get the high throught put or out come. can be flexible
for scaling.
ex: Flipkart or amazon sale offer-> search(read
opreations are more)->Write operations are less(buy product)-> to keep
both servies in sync use Messaging system(Kafka).
Saga Pattern-> Choreography Saga
pattern -> introduces Kafka in between microservices instead of using multiple
Http requests.
Microservices:
Log Aggregation
Externalized configuration
Service Registry & Service Discovery
Circuit Breaker
Loose coupling
High Cohesion
Side car pattern
Micro services Fallout Scenarios handling
For system or data faliure reqeusts
Can maintain Dead letter queue and Fallout queue so that
can reprocess them after few retries and to unblock other requests.
Understand scope of the problem
Health checks: actuator /health, /status
@Component
public class MyCustomHealthIndicator
implements HealthIndicator {
@Override
public Health health() {
1. Understand the Scope of the Problem:
·
Detection: The
first step is to detect that a microservice is down. This requires robust
monitoring and alerting.
- Health Checks: Implement
health check endpoints in each microservice (e.g., /health, /status).
These endpoints should return a 200 OK status if the service is healthy
and an error status if it's not.
- Monitoring
Tools: Use monitoring tools (e.g., Prometheus, Grafana,
Datadog, New Relic) to periodically check the health check endpoints of
each service.
- Alerting: Configure
alerts to notify you when a service's health check fails or when other
metrics (e.g., CPU usage, memory usage, error rate) exceed a certain
threshold.
- Isolation: Ensure
that the failure of one microservice doesn't cascade and bring down other
services.
2. Implement Fault Tolerance Patterns:
·
Circuit Breaker:
- Purpose: To
prevent a client from repeatedly trying to call a failing service, which
can waste resources and potentially overload the failing service.
- How it Works: The
circuit breaker monitors the number of failures. If the failure rate
exceeds a certain threshold, the circuit breaker "opens," and
subsequent calls to the service are immediately failed without even
attempting to connect. After a certain amount of time, the circuit
breaker enters a "half-open" state, where it allows a limited
number of calls to the service to see if it has recovered. If the calls
succeed, the circuit breaker "closes" and normal operation
resumes.
- Libraries: Hystrix
(Netflix, now in maintenance mode), Resilience4j (more actively
maintained).
- Retry:
- Purpose: To
automatically retry failed requests to a service, in case the failure was
transient (e.g., a temporary network glitch).
- How it Works: When a
request fails, the client automatically retries the request after a
certain delay. The delay can be fixed or exponential (increasing with
each retry).
- Considerations: Be
careful about retrying requests that are not idempotent (i.e., requests
that have side effects). Retrying a non-idempotent request could lead to
unintended consequences (e.g., creating duplicate orders).
- Fallback:
- Purpose: To provide an
alternative response when a service is unavailable.
- How it Works: When a
request fails, the client executes a fallback function that provides a
default value, retrieves data from a cache, or performs some other
action.
- Example: If a
product catalog service is down, the client could display a cached
version of the catalog or a default set of products.
- Bulkhead:
- Purpose: To
isolate different parts of your application so that a failure in one part
doesn't affect other parts.
- How it Works: The
bulkhead pattern limits the number of concurrent calls to a service. This
prevents a single failing service from consuming all of the resources of
the calling service.
- Rate Limiting:
- Purpose: To
prevent a client from overwhelming a service with too many requests.
- How it Works: The rate
limiting pattern limits the number of requests that a client can make to
a service within a certain time period. This can help to protect services
from denial-of-service attacks and prevent them from becoming overloaded.
3. Design for Idempotency:
- Definition: An
operation is idempotent if it can be executed multiple times without
changing the result beyond the initial application.
- Importance: Designing
your services to be idempotent makes it much easier to handle failures and
retries. If an operation is idempotent, you can safely retry it without
worrying about unintended side effects.
- Example: An
operation to set the quantity of an item in a shopping cart to 5 is
idempotent. An operation to increment the quantity of an item in a
shopping cart is not idempotent.
4. Implement Asynchronous Communication:
- Message Queues: Use
message queues (e.g., RabbitMQ, Kafka, ActiveMQ) to decouple services and
enable asynchronous communication.
- Benefits: If a
service is down, the messages will be queued and delivered when the
service comes back online. This improves the resilience of the system and
prevents data loss.
- Eventual
Consistency: Embrace eventual consistency, which means that data might not
be immediately consistent across all services, but it will eventually
become consistent.
5. Use Service Discovery and Load Balancing:
- Service Discovery: Use a
service discovery mechanism (e.g., Consul, etcd, ZooKeeper, Kubernetes
DNS) to allow services to dynamically locate each other.
- Load Balancing: Use a
load balancer (e.g., Nginx, HAProxy, Kubernetes Service) to distribute
traffic across multiple instances of a service.
- Benefits: If one
instance of a service goes down, the load balancer will automatically
redirect traffic to the remaining instances.
6. Implement Proper Monitoring and Logging:
- Centralized Logging: Use a
centralized logging system (e.g., ELK stack, Splunk) to collect and
analyze logs from all services.
- Distributed Tracing: Use
distributed tracing (e.g., Jaeger, Zipkin) to track requests as they flow
through the system.
- Benefits: This
makes it easier to identify the root cause of failures and to monitor the
performance of the system.
7. Use Container Orchestration (e.g., Kubernetes):
- Self-Healing: Container
orchestration platforms like Kubernetes provide self-healing capabilities,
such as automatically restarting failed containers.
- Scaling: They also
make it easy to scale services up or down based on demand.
- Service Discovery: Kubernetes
provides built-in service discovery and load balancing.
8. Consider a Service Mesh (e.g., Istio, Linkerd):
- Traffic Management: Service
meshes provide advanced traffic management capabilities, such as traffic
shaping, canary deployments, and A/B testing.
- Security: They also
provide security features, such as mutual TLS authentication and
authorization policies.
- Observability: Service
meshes enhance observability by providing detailed metrics and traces.
Example Scenario (Order Service Depends on Payment
Service):
- Payment Service Down: The
Payment Service becomes unavailable.
- Order Service Detects
Failure: The Order Service's health checks to the Payment Service start
failing.
- Circuit Breaker Opens: The
Circuit Breaker in the Order Service opens, preventing further calls to
the Payment Service.
- Fallback Mechanism: The Order
Service uses a fallback mechanism:
- If the payment was already
attempted and failed, the Order Service displays an error message to the
user, suggesting they try again later.
- If the payment hasn't been
attempted yet, the Order Service queues the order for later processing
(using a message queue) and notifies the user that their order is
pending.
- Monitoring and Alerting: The
monitoring system alerts the operations team about the Payment Service
failure.
- Payment Service Recovery: The
operations team fixes the Payment Service issue, and it comes back online.
- Circuit Breaker Closes: The
Circuit Breaker in the Order Service closes, and normal communication with
the Payment Service resumes.
- Queued Orders Processed: The Order
Service processes the queued orders.
Key Takeaways:
- Proactive Monitoring: Invest in
robust monitoring and alerting to detect failures quickly.
- Embrace Fault Tolerance: Implement
fault tolerance patterns to prevent failures from cascading and to provide
a good user experience.
- Design for Resilience: Design
your services to be resilient to failures. This includes using
asynchronous communication, service discovery, and load balancing.
- Automate Recovery: Automate
as much of the recovery process as possible to reduce downtime.
- Continuous Improvement: Continuously
monitor and improve your failure handling strategies.
normalization basics
JWT TOCKEN SpringSecurity-> GCP cloud run
GCP apigee gatway
document db basics
install docment db and nosql
check for AWS serices
ECS, S3, TERRFORM, LAMDA
k8 kubeclt commands
to create build and push and pull commands
deploy
get
scale
replica
logs
all kubectl commands
service,
deply file
pods files and all.
configmap files.
Hibernate caches
- Client->
1time queried DB
-
->Same session 2 time quired
DB-> fetch data it from 1st level cache.->HIbernate provides it by
default.
- Same User or
Another user in different or 2nd session-> same query-> it doest
not have data in first level cache of session2 so it agian hits db.->
need to go for 2nd level cache.
- ->All the
sessions can use 2nd level cache-> thirdparty caches ehcache, OS, swam
- Jpa save and
persist methods and all..
@Persistance context by EntityManager
- creates or
saves new reocrd, if any already record exist with id-> thorows
exception, doesn't update it.
- doesn't not
return any entity
- Standard
JPA
Reactive programming->
Event looping
Unsynchronous and Nonblocking.
Can accept multiple request for a thread -> and
subscribe to db for respposne
DataFlow as eveng driven stream
Subscribe to db-> if any udpates happened to DB also we
can get the all update data. Ex: Live Cricket score board.
Back pressure on data streams-> app
can tell to db wait for some time until I process existing records.
PubSub Mono
Kafka: Distributed messaging system.
·
acks=0
·
acks=all or acks=-1
·
Properties props = new Properties();
·
props.put("bootstrap.servers", "kafka1:9092,kafka2:9092,kafka3:9092");
·
props.put("acks", "all");
·
props.put("retries", 3);
·
props.put("enable.idempotence", "true");
·
props.put("max.in.flight.requests.per.connection",
"1");
·
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
·
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
·
props.put("delivery.timeout.ms", "120000");
·
ProducerRecord<String, String> record = new
ProducerRecord<>("my-topic", "key", "value");
·
producer.send(record, (metadata, exception) -> {
Checklist for Ensuring Message Delivery:
·
Set acks=all (or acks=-1) on the producer.
·
Set retries to a reasonable value (e.g., 3-10) on
the producer.
·
Enable enable.idempotence=true on the producer
(Kafka >= 0.11).
·
Set max.in.flight.requests.per.connection=1 on
the producer (in combination with idempotence and acks=all).
·
Set delivery.timeout.ms to a sufficiently high
value on the producer.
·
Set replication.factor to 3 (or higher) on the
topic.
·
Set min.insync.replicas to 2 (or higher) on the
topic.
Spring Boot Optimization
Optimize
Configuration
1. Use
Profiles-> for env speicific config
2. Avoid
over config-> Use auto configuration feature
3. Lazy
initialization(spring.main.lazy-initialization=true)
Improve
Database Performance
1. Use
connection pooling
2. Indexing
3. Use
cache
4. Batch
Operations
Optimize
JVM & Garbage collection
JMV
tuning-> approprate heap size -Xmx - Xms
Garbage
collector algorithem ->ZGC
Reduce
start up time
Remove
unused starters
@Component
scan liimt to package
Customer
Banner
Optimize
application logic
Avoid
heavy logic in Controllers ->Logic shouldbe in service layer instead of
controller layer.
Efficient
data structures
Use
nAysnc or Reactive or parlell processing-> non blocking operations.
Optiimze
API Performance
GZIP
compression-> Enable compression to reduce response
time(server.compresssion.enable=true)
Pagination
and filtering
Timeouts
and Retries
Optimize
Security
Disable
unused Features-> deisbale unused actuators endpoints in production
Use
stateliess sission
Toien
based authentication
Use
Monitoring and Profiling tools
ELK,
Actuator,
Jprofiler
Optimse
Deployment
->
use Docker, K8
Scale
Horizantally by deploying multiple instances
Use
Cloud native
Regular
cdoe and dependcney updates-> remvoe dead code
----------------------------------------------------------------------------
Advantages of Microservices
1.
Scalability->independently.
2.
Flexibility in tech stack->
different services can use different programming language
3.
Faster Development &
Deployment->Teams can work parlally independtly on different services,
independent deployment.
4.
Improved fault Isolation-> one
service fail -> less impact in entire system.
5.
Easier Maintance and Debugging->
Debugging and testing individual services are easier, simpler compared to
Monolithic.
6.
Agility & Faster time to Market->Supports
shorter deployment cycles due to decoupled components.
7.
Team Autonomy-> Team
can own speicific services-> increase productivity.
Challenges of using Microservices
1.
Increased complexity-> managing
mulitple services introduing complexity in communication, deployment and
monitoring
2.
Network latency & Reliability->
communication in network latency and failures disrupt system.
3.
Data Management-> Managing
distributed data across multipe services is challendgin-> event or
SagaPattern
4.
DevOps overhead-> complex
in configuring and managing containiration and orchestration tools
5.
Security-> more
services means more surface for attackers.
6.
Cost-> additioanl
infra for cont, orche and logging
7.
Team Coordination
K8 Features
1.
Container Orchestration->Automatically
schedules and manages deployments of containers accross cluster of machines
2.
Scalbility
3.
Load Balancing, High availability
4.
Self Healing->
Restarts contianer-> kills container that donot respond fto health checks.
5.
Declarative configuration->
Cofigmap, secret map, YML
6.
Service Discovery->DNS nanes
with out IP address, with service names finds other services.
7.
Automated rollout and rollbaceks
8.
Monitoring and logging
9.
Extensiblity
10. HIgh
availabilty
11. Resource
ooptimization-> Uses quitosa nd liimts to contorl the resuorceon pod
and namespace level.
12. CICD
integration
13. cli(command
line interface)
14. Faoult
tolrance-> redistributes load from falied nodes to healthy ones.
Micro services 12 factors
1.
OneCodebase-> one
code base for service and deployble to multiple envs.
2.
Dependencies-> Explicitlyl
declare and Isolate dependencies to enseure consistency
3.
Configuraiton-> Speerate
from code base-> env variables
4.
Backing services-> DBs
& message brokcers as attached resources->flexiblity replace.
5.
Build,Relsae, Run-> CI/CD
automates
6.
Processes-> exceute
app in stateless proces and persiste data in exteranl backing servies.
7.
Port Binidg->Export
services via prot to enable external comminiation.
8.
Concurrncy-> k8
scaling of mulitple serices.
9.
Disposiblity->
Maximize roubustness with fast startups and graceful shutdownd.
10. Dev/Prod
Parity-> all envs shuld be similar configuration
11. Logs->event
streaming-> ELK
12.
Admin processes-> Use
job scheduler to run backgrouknd tasks->seperate process.
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + jwt);
HttpEntity<String> request = new HttpEntity<>(headers);
String response = restTemplate.exchange(userServiceUrl, HttpMethod.GET, request, String.class).getBody();
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://auth.example.com
spring.security.oauth2.resourceserver.jwt.audience=service-name
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}