服务生产与消费
在微服务架构中,服务提供者和服务消费者是两个核心概念,它们定义了微服务之间的关系和通信方式。
服务提供者是指提供某个具体功能或服务的微服务。它负责实现和暴露一组API接口,供其他微服务或客户端调用。服务提供者将自身的功能封装成服务,并通过网络暴露给外部。它可以是一个独立的微服务,也可以是由多个微服务组成的服务集群。
服务消费者是指依赖某个功能或服务的微服务或客户端。它需要通过调用服务提供者暴露的API接口来获取所需的功能或数据。服务消费者通过网络请求服务提供者,并处理返回的结果。消费者可以根据自己的需求,选择调用适当的服务提供者。
在微服务架构中,服务提供者和服务消费者之间的通信通常是通过远程调用来实现的。服务提供者通过公开API接口,提供了一组可以被调用的方法或服务。服务消费者可以通过网络请求这些API接口,以获取所需的功能或数据。
通过微服务的服务提供者-服务消费者模式,不同的微服务可以独立开发、部署和扩展,它们之间通过明确定义的接口进行通信,实现了解耦和灵活性。
这种模式还允许不同的团队独立地开发和维护各自的微服务,提高了开发效率和系统的可扩展性。
服务提供者
前面已经将用户服务注册到了eureka注册中心,但是还没有暴漏任何API给服务消费者调用。
模拟开发
Entity.User
注意导包的层级结构。

package cn.yuchaoit.userservice.entity;
public class User {
private int id;
private String name;
private int age;
private String sex;
public int getAge() {
return age;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public void setAge(int age) {
this.age = age;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
}
UserController.java

package cn.yuchaoit.userservice.controller;
import cn.yuchaoit.userservice.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.Random;
@RestController
public class UserController {
@GetMapping("/user")
public String getUserService(){
return "this is user-service";
}
@GetMapping("/user-nums")
public Integer getUserNums(){
return new Random().nextInt(100);
}
//{"id": 123, "name": "张三", "age": 20, "sex": "male"}
@GetMapping("/user/{id}")
public User getUserInfo(@PathVariable("id") int id){
User user = new User();
user.setId(id);
user.setAge(20);
user.setName("zhangsan");
user.setSex("male");
return user;
}
}
application.yml
增加从环境变量中读取EUREKA_SERVER和EUREKA_INSTANCE_HOSTNAME配置
server:
port: 7000
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://${EUREKA_USER:admin}:${EUREKA_PASS:admin}@localhost:8761/eureka/}
instance:
instance-id: ${EUREKA_INSTANCE_HOSTNAME:${eureka.instance.hostname}:${server.port}}
prefer-ip-address: true
hostname: user-service
lease-renewal-interval-in-seconds: 2
lease-expiration-duration-in-seconds: 2
spring:
application:
name: user-service
重启测试API


k8s部署user-service
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: yuchao
spec:
replicas: 1
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
imagePullSecrets:
- name: registry-10.0.0.66
containers:
- name: user-service
image: 10.0.0.66:5000/spring-cloud/user-service
imagePullPolicy: IfNotPresent
ports:
- containerPort: 7000
resources:
requests:
memory: 400Mi
cpu: 50m
limits:
memory: 2Gi
cpu: 2000m
env:
- name: EUREKA_SERVER
value: "http://admin:admin@eureka-cluster-0.eureka:8761/eureka/,http://admin:admin@eureka-cluster-1.eureka:8761/eureka/,http://admin:admin@eureka-cluster-2.eureka:8761/eureka/"
- name: EUREKA_INSTANCE_HOSTNAME
valueFrom:
fieldRef:
fieldPath: metadata.name
service
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: yuchao
spec:
ports:
- port: 7000
protocol: TCP
targetPort: 7000
selector:
app: user-service
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: user-service
namespace: yuchao
spec:
ingressClassName: nginx
rules:
- host: user-service.yuchaoit.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: user-service
port:
number: 7000
代码推送
git init
git remote add origin http://gitlab.yuchaoit.cn/spring-cloud/user-service.git
git add .
git commit -m "Initial commit"
git push -u origin master

制作镜像
# mvn,jdk环境检查
[root@docker01 ~/springcloud/user-service]#tail -5 /etc/profile
export PATH=$PATH:/opt/apache-maven-3.3.9/bin
export JAVA_HOME=/opt/jdk8
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
You have new mail in /var/spool/mail/root
[root@docker01 /opt/jdk1.8.0_221]#ln -s /opt/jdk1.8.0_221/ /opt/jdk8
[root@docker01 /opt/jdk1.8.0_221]#source /etc/profile
[root@docker01 /opt/jdk1.8.0_221]#java -version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
[root@docker01 /opt/jdk1.8.0_221]#
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:03 min
[INFO] Finished at: 2023-05-17T14:53:32+08:00
[INFO] Final Memory: 44M/210M
[INFO] ------------------------------------------------------------------------
You have new mail in /var/spool/mail/root
[root@docker01 ~/springcloud/user-service]#mvn clean package
# 2.打包镜像
[root@docker01 ~/springcloud/user-service]#
[root@docker01 ~/springcloud/user-service]#cat Dockerfile
FROM openjdk:8-jdk-alpine
COPY target/user-service-0.0.1-SNAPSHOT.jar app.jar
ENV JAVA_OPTS=""
CMD [ "sh", "-c", "java $JAVA_OPTS -jar /app.jar" ]
[root@docker01 ~/springcloud/user-service]#docker build . -t 10.0.0.66:5000/spring-cloud/user-service
# 3.推送镜像
[root@docker01 ~/springcloud/user-service]#docker push 10.0.0.66:5000/spring-cloud/user-service
Using default tag: latest
The push refers to repository [10.0.0.66:5000/spring-cloud/user-service]
1850abd31d74: Pushed
ceaf9e1ebef5: Mounted from spring-cloud/eureka-cluster
9b9b7f3d56a0: Mounted from spring-cloud/eureka-cluster
f1b5933fe4b5: Mounted from spring-cloud/eureka-cluster
latest: digest: sha256:5760e10d74dfe43955ff63af43e5df3ee11c957f4b88d44b61baa1ab63866d9c size: 1159
You have mail in /var/spool/mail/root
[root@docker01 ~/springcloud/user-service]#
启动访问user-service
[root@k8s-master ~/springcloud]#kubectl apply -f .
ingress.networking.k8s.io/user-service created
service/user-service created
deployment.apps/user-service created
[root@k8s-master ~/springcloud]#kubectl -n yuchao get po
NAME READY STATUS RESTARTS AGE
eladmin-api-7496b69c-dr9jk 1/1 Running 11 (47h ago) 5d22h
eladmin-web-7458474b64-mgrwp 1/1 Running 10 (25h ago) 27d
eureka-cluster-0 1/1 Running 0 20h
eureka-cluster-1 1/1 Running 0 20h
eureka-cluster-2 1/1 Running 0 20h
mysql-559d5fcc8b-vnpzf 1/1 Running 1 (25h ago) 2d21h
redis-7957d49f44-5mctq 1/1 Running 2 (25h ago) 2d21h
user-service-8544d8b7bb-kmgbx 1/1 Running 0 19s
yuchao-ngx 1/1 Running 14 (25h ago) 40d
[root@k8s-master ~/springcloud]#

k8s部署结束

查看注册中心(重要)
[root@k8s-master ~/springcloud]#kubectl -n yuchao get po |grep user
user-service-5997c9d59f-ftc2c 1/1 Running 0 2m20s
user-service-5997c9d59f-rs2tx 1/1 Running 0 9s
user-service-5997c9d59f-wf2gw 1/1 Running 0 9s
user-service-5997c9d59f-xgzdb 1/1 Running 0 2m20s
[root@k8s-master ~/springcloud]#
# 服务节点,就是pod名字了

每一个后端服务,只要启动后,会自动注册自己到注册中心,其他系统,只需要来Eureka里找节点就行。
以后直接通过USER_SERVICE就可以负载均衡,访问具体服务。
服务消费者
创建bill-service项目
新的模块初始化三部曲:
- pom.xml
- 启动类
- 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.yuchaoit</groupId>
<artifactId>bill-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>bill-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
上述的包,maven本地都有了
application.yml
server:
port: 7001
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER:http://admin:admin@localhost:8761/eureka/}
instance:
instance-id: ${eureka.instance.hostname}:${server.port}
prefer-ip-address: true
hostname: ${INSTANCE_HOSTNAME:bill-service}
#eureka客户端需要多长时间发送心跳给eureka服务器,表明他仍然或者,默认30秒
lease-renewal-interval-in-seconds: 2
#eureka服务器在接受到实例的最后一次发出的心跳后,需要等待多久才可以将此实例删除
lease-expiration-duration-in-seconds: 2
spring:
application:
name: bill-service
BillController(微服务调用)
传统调用
package cn.yuchaoit.billservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class BillController {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
@GetMapping("/bill/user")
public String getUserInfo(){
return restTemplate.getForObject("http://localhost:7000/user", String.class);
}
}
微服务调用
package cn.yuchaoit.billservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class BillController {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
@GetMapping("/bill/user")
public String getUserInfo(){
return restTemplate.getForObject("http://user-service/user", String.class);
}
}
BillServiceApplication启动类型
package cn.yuchaoit.billservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class BillServiceApplication {
public static void main(String[] args) {
SpringApplication.run(BillServiceApplication.class, args);
}
}
启动bill账单服务
账单是和用户关联的,需要去调取用户信息
main] c.y.billservice.BillServiceApplication : No active profile set, falling back to default profiles: default
2023-05-17 16:35:13.766 INFO 12532 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=8459d36c-3fcb-3e53-bdc9-3512c96e62ff
2023-05-17 16:35:13.918 INFO 12532 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 7001 (http)

服务端口7001,访问试试

小结
完成bill-service > user-service的调用,这里只是为了理解服务调用的概念,两套系统通过远程访问,如restfulAPI
当然在代码层面,微服务框架,本身还存在负载均衡算法等知识点,这些不属于运维层面理解。
