第33章 - Go语言 云原生开发

第33章 - 云原生开发将深入探讨云原生技术及其在现代软件开发中的应用。我们将从云原生的基本概念开始,逐步介绍Kubernetes的基本使用方法,并结合具体的云服务提供商实例,通过Go语言编写的应用程序来展示如何实现云原生开发。

33.1 云原生的概念

云原生(Cloud Native)是一种构建和运行应用程序的方法,它充分利用云计算的优势,以快速、灵活、可扩展的方式开发和部署应用。云原生应用通常具备以下特点:

  • 微服务架构:将应用拆分为一系列小的服务,每个服务实现特定的业务功能,并且可以独立地进行开发、测试、部署和扩展。
  • 容器化:使用容器(如Docker)来打包应用及其依赖,确保应用在不同环境中具有一致的行为。
  • 持续集成/持续部署 (CI/CD):自动化地构建、测试和部署应用,加快软件交付速度。
  • 动态管理:利用云平台提供的服务自动管理应用的生命周期,包括负载均衡、自动扩缩容等。
  • 面向服务的架构:强调服务之间的解耦,使系统更加模块化,易于维护和更新。

33.2 Kubernetes入门

Kubernetes(简称K8s)是一个开源的容器编排平台,用于自动部署、扩展和管理容器化的应用。Kubernetes的主要组件包括:

  • Pods:Kubernetes中最小的部署单元,可以包含一个或多个容器。
  • Services:定义了访问Pods的方式,提供负载均衡和网络服务发现。
  • Deployments:描述了应用的理想状态,Kubernetes会自动保证这个状态。
  • ReplicaSets:确保任意时刻都有指定数量的Pod副本处于运行状态。
  • Volumes:为Pods提供存储卷,支持数据持久化。

33.3 云服务提供商

云服务提供商(CSPs)提供了丰富的服务来支持云原生开发,例如:

  • 阿里云:提供了一站式的云原生解决方案,包括容器服务ACK、Serverless应用引擎SAE等。
  • AWS:Amazon Web Services 提供了广泛的云原生服务,如EKS(Elastic Kubernetes Service)、Lambda等。
  • Google Cloud:提供了GKE(Google Kubernetes Engine)等服务,支持高效管理和扩展Kubernetes集群。

33.4 结合案例及源代码

假设我们正在开发一个基于Go语言的简单Web应用,该应用将部署在一个Kubernetes集群上,并使用阿里云的容器服务ACK来管理这个集群。

应用设计

我们的应用将是一个简单的RESTful API服务器,提供用户信息的查询和创建功能。

技术栈
  • 后端:Go语言 + Gin框架
  • 数据库:MySQL
  • 容器化:Docker
  • 编排:Kubernetes
  • 云服务:阿里云容器服务ACK
源代码示例

下面是一个简单的Go应用示例,使用Gin框架实现了一个基本的API接口。

package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 路由处理r.GET("/users", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "Hello from the user service!",})})// 启动服务r.Run(":8080")
}
Dockerfile

为了容器化我们的应用,我们需要创建一个Dockerfile文件:

FROM golang:1.17-alpine as builder
WORKDIR /app
COPY . .
RUN go build -o app .FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/app .
CMD ["./app"]
部署到Kubernetes

创建一个Kubernetes Deployment和Service来部署我们的应用:

apiVersion: apps/v1
kind: Deployment
metadata:name: go-web-app
spec:replicas: 3selector:matchLabels:app: go-webtemplate:metadata:labels:app: go-webspec:containers:- name: go-webimage: your-docker-repo/go-web-app:latestports:- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:name: go-web-service
spec:selector:app: go-webports:- protocol: TCPport: 80targetPort: 8080type: LoadBalancer
使用阿里云ACK
  1. 在阿里云控制台创建一个新的Kubernetes集群。
  2. 将上面的YAML文件应用到你的集群中,可以通过kubectl apply -f deployment.yaml命令完成。
  3. 访问Service的外部IP地址,测试你的应用是否正常工作。

33.5 优化应用性能

在云原生环境中,优化应用性能是至关重要的。以下是一些常见的优化策略:

1. 资源限制与请求

在Kubernetes中,可以为Pod设置资源限制(limits)和请求(requests),以确保每个Pod都能获得所需的资源,同时防止某个Pod占用过多资源导致其他Pod资源不足。

apiVersion: v1
kind: Pod
metadata:name: example-pod
spec:containers:- name: example-containerimage: your-imageresources:requests:memory: "64Mi"cpu: "250m"limits:memory: "128Mi"cpu: "500m"
2. 水平自动扩展

Kubernetes提供了Horizontal Pod Autoscaler(HPA),可以根据CPU使用率或其他自定义指标自动调整Pod的数量。

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:name: go-web-app-hpa
spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: go-web-appminReplicas: 3maxReplicas: 10metrics:- type: Resourceresource:name: cputarget:type: UtilizationaverageUtilization: 50
3. 缓存与CDN

使用缓存和内容分发网络(CDN)可以显著提高应用的响应时间和用户体验。例如,可以使用Redis作为缓存层,或者使用阿里云的CDN服务来加速静态资源的加载。

33.6 确保应用安全性

在云原生环境中,安全是不可忽视的重要方面。以下是一些常见的安全措施:

1. 网络策略

Kubernetes网络策略(Network Policies)可以控制Pod之间的通信,确保只有授权的流量才能到达目标Pod。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: go-web-app-policy
spec:podSelector:matchLabels:app: go-webingress:- from:- podSelector:matchLabels:app: frontendports:- protocol: TCPport: 8080
2. 身份验证与授权

使用OAuth2、OpenID Connect等协议进行身份验证和授权,确保只有经过认证的用户才能访问应用的敏感数据。

3. 加密传输

使用HTTPS协议加密传输数据,确保数据在传输过程中不被窃取或篡改。

33.7 利用云服务提供商的高级特性

云服务提供商通常提供许多高级特性来提升应用的可靠性和可维护性。以下是一些常见的高级特性:

1. 监控与日志

使用阿里云的ARMS(Application Real-Time Monitoring Service)和SLS(Log Service)来监控应用的性能和日志,及时发现并解决问题。

2. 备份与恢复

利用阿里云的RDS(Relational Database Service)自动备份功能,确保数据的安全性和可恢复性。

3. 服务网格

使用阿里云的服务网格ASM(Alibaba Cloud Service Mesh)来管理微服务之间的通信,提供统一的服务治理能力。

33.8 实战案例

假设我们正在开发一个电商应用,该应用需要处理大量的用户请求和数据操作。以下是具体的技术方案和步骤:

1. 应用架构
  • 前端:React应用,托管在阿里云OSS(Object Storage Service)上,使用CDN加速。
  • 后端:Go语言开发的API服务,使用Gin框架。
  • 数据库:MySQL,托管在阿里云RDS上。
  • 缓存:Redis,托管在阿里云KVStore上。
  • 消息队列:RabbitMQ,托管在阿里云MQ上。
  • 容器编排:Kubernetes,使用阿里云ACK管理。
2. 部署流程
  1. 代码仓库:将应用代码托管在GitHub或GitLab上。
  2. 持续集成/持续部署(CI/CD):使用Jenkins或GitHub Actions自动化构建和测试流程。
  3. 镜像构建:使用Docker构建应用镜像,并推送到阿里云CR(Container Registry)。
  4. Kubernetes部署:使用Helm或Kustomize管理Kubernetes资源文件,通过kubectl命令将应用部署到ACK集群。
  5. 服务发现:使用Kubernetes的Service和Ingress资源进行服务发现和路由管理。
  6. 监控与告警:使用Prometheus和Grafana监控应用性能,使用Alertmanager配置告警规则。
3. 示例代码

以下是一个简单的Go应用示例,展示了如何连接到MySQL数据库并执行查询操作:

package mainimport ("database/sql""fmt""log""net/http"_ "github.com/go-sql-driver/mysql""github.com/gin-gonic/gin"
)var db *sql.DBfunc initDB() {var err errordsn := "user:password@tcp(db-service:3306)/dbname"db, err = sql.Open("mysql", dsn)if err != nil {log.Fatal(err)}if err = db.Ping(); err != nil {log.Fatal(err)}
}func getUser(c *gin.Context) {rows, err := db.Query("SELECT id, name FROM users")if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}defer rows.Close()var users []map[string]interface{}for rows.Next() {var id intvar name stringif err := rows.Scan(&id, &name); err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}users = append(users, map[string]interface{}{"id": id, "name": name})}c.JSON(http.StatusOK, users)
}func main() {initDB()defer db.Close()r := gin.Default()r.GET("/users", getUser)r.Run(":8080")
}
4. Dockerfile
FROM golang:1.17-alpine as builder
WORKDIR /app
COPY . .
RUN go build -o app .FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/app .
CMD ["./app"]
5. Kubernetes资源配置
apiVersion: apps/v1
kind: Deployment
metadata:name: go-web-app
spec:replicas: 3selector:matchLabels:app: go-webtemplate:metadata:labels:app: go-webspec:containers:- name: go-webimage: your-docker-repo/go-web-app:latestports:- containerPort: 8080env:- name: MYSQL_HOSTvalue: "db-service"- name: MYSQL_PORTvalue: "3306"- name: MYSQL_USERvalue: "user"- name: MYSQL_PASSWORDvalue: "password"- name: MYSQL_DBvalue: "dbname"
---
apiVersion: v1
kind: Service
metadata:name: go-web-service
spec:selector:app: go-webports:- protocol: TCPport: 80targetPort: 8080type: LoadBalancer

33.9 总结

通过本章的学习,我们深入了解了云原生开发的核心概念和技术栈,掌握了如何使用Kubernetes和阿里云服务来构建、部署和管理云原生应用。通过实际的案例和源代码,我们展示了如何优化应用性能、确保应用安全,并利用云服务提供商的高级特性来提升应用的可靠性和可维护性。

接下来我们将继续深入探讨一些高级主题,包括如何进行故障排除、如何实现多环境管理、如何进行灰度发布和蓝绿部署,以及如何利用云原生工具进行持续集成和持续部署(CI/CD)。

33.10 故障排除

在云原生环境中,故障排除是一项重要技能。以下是一些常见的故障排除方法和工具:

1. 日志分析

使用Kubernetes的kubectl logs命令查看Pod的日志,帮助诊断应用问题。

kubectl logs <pod-name>

如果应用使用了集中式日志系统(如阿里云SLS),可以通过日志搜索和分析工具来快速定位问题。

2. 事件查看

使用kubectl get events命令查看集群中的事件,了解Kubernetes资源的状态变化。

kubectl get events --sort-by=.metadata.creationTimestamp
3. 网络调试

使用kubectl exec命令进入Pod内部,使用网络工具(如curlnetstat)进行网络调试。

kubectl exec -it <pod-name> -- /bin/sh
4. 性能监控

使用Prometheus和Grafana监控应用的性能指标,如CPU使用率、内存使用率、请求延迟等。

33.11 多环境管理

在云原生开发中,通常需要管理多个环境,如开发环境、测试环境和生产环境。以下是一些常见的多环境管理方法:

1. Kubernetes命名空间

使用Kubernetes命名空间(Namespace)隔离不同的环境,每个环境使用一个独立的命名空间。

apiVersion: v1
kind: Namespace
metadata:name: dev
---
apiVersion: v1
kind: Namespace
metadata:name: test
---
apiVersion: v1
kind: Namespace
metadata:name: prod
2. 配置管理

使用ConfigMap和Secret管理环境变量和敏感信息,避免硬编码在代码中。

apiVersion: v1
kind: ConfigMap
metadata:name: app-config
data:app.env: "dev"app.log.level: "debug"
---
apiVersion: v1
kind: Secret
metadata:name: app-secret
type: Opaque
data:db.password: <base64-encoded-password>
3. 环境变量注入

在Deployment中注入环境变量,根据不同的环境配置不同的值。

apiVersion: apps/v1
kind: Deployment
metadata:name: go-web-app
spec:replicas: 3selector:matchLabels:app: go-webtemplate:metadata:labels:app: go-webspec:containers:- name: go-webimage: your-docker-repo/go-web-app:latestports:- containerPort: 8080envFrom:- configMapRef:name: app-config- secretRef:name: app-secret

33.12 灰度发布和蓝绿部署

灰度发布和蓝绿部署是两种常见的发布策略,可以帮助减少新版本上线的风险。

1. 灰度发布

灰度发布是指在新版本完全上线之前,先让一部分用户使用新版本,收集反馈和监控数据,再决定是否全面推广。

示例

使用Kubernetes的Ingress和Service实现灰度发布。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: go-web-ingressannotations:nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-weight: "10"
spec:rules:- host: example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: go-web-canaryport:number: 80
---
apiVersion: v1
kind: Service
metadata:name: go-web-canary
spec:selector:app: go-web-canaryports:- protocol: TCPport: 80targetPort: 8080
2. 蓝绿部署

蓝绿部署是指在新版本上线时,保留旧版本的运行环境,新版本在新的环境中运行,确认无误后再切换流量到新版本。

示例

使用Kubernetes的Deployment和Service实现蓝绿部署。

apiVersion: apps/v1
kind: Deployment
metadata:name: go-web-app-green
spec:replicas: 3selector:matchLabels:app: go-web-greentemplate:metadata:labels:app: go-web-greenspec:containers:- name: go-webimage: your-docker-repo/go-web-app:latestports:- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:name: go-web-service
spec:selector:app: go-web-greenports:- protocol: TCPport: 80targetPort: 8080type: LoadBalancer

33.13 持续集成和持续部署(CI/CD)

CI/CD是现代软件开发的重要实践,可以帮助团队更快、更可靠地交付软件。以下是一些常见的CI/CD工具和实践:

1. GitHub Actions

GitHub Actions是一个强大的CI/CD工具,可以直接在GitHub仓库中配置流水线。

示例

创建一个.github/workflows/ci-cd.yml文件,配置CI/CD流水线。

name: CI/CD Pipelineon:push:branches:- mainjobs:build-and-deploy:runs-on: ubuntu-lateststeps:- name: Checkout codeuses: actions/checkout@v2- name: Set up Gouses: actions/setup-go@v2with:go-version: 1.17- name: Build applicationrun: go build -o app .- name: Build Docker imagerun: docker build -t your-docker-repo/go-web-app:latest .- name: Push Docker imagerun: |echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdindocker push your-docker-repo/go-web-app:latest- name: Deploy to Kubernetesrun: |kubectl apply -f k8s/deployment.yamlkubectl apply -f k8s/service.yamlenv:KUBECONFIG: ${{ secrets.KUBECONFIG }}
2. Jenkins

Jenkins是一个流行的CI/CD工具,支持多种插件和集成方式。

示例

创建一个Jenkinsfile,配置CI/CD流水线。

pipeline {agent anystages {stage('Checkout') {steps {git 'https://github.com/your-repo/go-web-app.git'}}stage('Build') {steps {sh 'go build -o app .'}}stage('Test') {steps {sh 'go test ./...'}}stage('Build Docker Image') {steps {sh 'docker build -t your-docker-repo/go-web-app:latest .'}}stage('Push Docker Image') {steps {withCredentials([usernamePassword(credentialsId: 'docker-credentials', usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {sh '''echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdindocker push your-docker-repo/go-web-app:latest'''}}}stage('Deploy to Kubernetes') {steps {withKubeConfig([credentialsId: 'kubeconfig-credentials']) {sh 'kubectl apply -f k8s/deployment.yaml'sh 'kubectl apply -f k8s/service.yaml'}}}}
}

33.14 总结

通过本章的学习,我们不仅深入探讨了云原生开发的核心概念和技术栈,还学习了如何进行故障排除、多环境管理、灰度发布和蓝绿部署,以及如何利用CI/CD工具实现持续集成和持续部署。

希望这些内容能够帮助你在云原生开发的道路上更进一步,构建出高效、稳定、可扩展的应用。如果你有任何问题或需要进一步的帮助,请随时联系我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62302.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分析JHTDB数据库的Channel5200数据集的数据(SciServer服务器)

代码来自https://github.com/idies/pyJHTDB/blob/master/examples/channel.ipynb %matplotlib inline import numpy as np import math import random import pyJHTDB import matplotlib.pyplot as plt import time as ttN 3 T pyJHTDB.dbinfo.channel5200[time][-1] time …

《Vue零基础入门教程》第十二课:双向绑定指令

往期内容 《Vue零基础入门教程》第六课&#xff1a;基本选项 《Vue零基础入门教程》第八课&#xff1a;模板语法 《Vue零基础入门教程》第九课&#xff1a;插值语法细节 《Vue零基础入门教程》第十课&#xff1a;属性绑定指令 《Vue零基础入门教程》第十一课&#xff1a;事…

windows 应用 UI 自动化实战

UI 自动化技术架构选型 UI 自动化是软件测试过程中的重要一环&#xff0c;网络上也有很多 UI 自动化相关的知识或资料&#xff0c;具体到 windows 端的 UI 自动化&#xff0c;我们需要从以下几个方面考虑&#xff1a; 开发语言 毋庸置疑&#xff0c;在 UI 自动化测试领域&am…

linux部署Whisper 视频音频转文字

github链接&#xff1a;链接 我这里使用anaconda来部署&#xff0c;debian12系统&#xff0c;其他linux也同样 可以使用gpu或者cpu版本&#xff0c;建议使用n卡&#xff0c;rtx3060以上 一、前期准备 1.linux系统 链接&#xff1a;debian安装 链接&#xff1a;ubuntu安装 …

MySQL聚合查询分组查询联合查询

#对应代码练习 -- 创建考试成绩表 DROP TABLE IF EXISTS exam; CREATE TABLE exam ( id bigint, name VARCHAR(20), chinese DECIMAL(3,1), math DECIMAL(3,1), english DECIMAL(3,1) ); -- 插入测试数据 INSERT INTO exam (id,name, chinese, math, engli…

Rust学习笔记_03——元组

Rust学习笔记_01——基础 Rust学习笔记_02——数组 Rust学习笔记_03——元组 文章目录 Rust学习笔记_03——元组元组1. 定义元祖2. 访问元组中的元素3. 元组的解构4. 元组不可遍历和切片5. 元组作为函数返回值6. 单元元组7. 代码演示 元组 在Rust编程语言中&#xff0c;元组&a…

mini-spring源码分析

IOC模块 关键解释 beanFactory&#xff1a;beanFactory是一个hashMap, key为beanName, Value为 beanDefination beanDefination: BeanDefinitionRegistry&#xff0c;BeanDefinition注册表接口&#xff0c;定义注册BeanDefinition的方法 beanReference&#xff1a;增加Bean…

redis学习面试

1、数据类型 string 增删改查 set key valueget keydel kstrlen k 加减 incr articleincrby article 3decr articledecyby article 取v中特定位置数据 getrange name 0 -1getrange name 0 1setrange name 0 x 设置过期时间 setex pro 10 华为 等价于 set pro 华为expire pro…

详解MVC架构与三层架构以及DO、VO、DTO、BO、PO | SpringBoot基础概念

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天毛毛张分享的是SpeingBoot框架学习中的一些基础概念性的东西&#xff1a;MVC结构、三层架构、POJO、Entity、PO、VO、DO、BO、DTO、DAO 文章目录 1.架构1.1 基本…

KST-3D01型胎儿超声仿真体模、吸声材料以及超声骨密度仪用定量试件介绍

一、KST-3D01型胎儿超声仿真体模 KST—3D01型胎儿超声体模&#xff0c;采用仿羊水环境中内置胎龄为7个月大仿胎儿设计。用于超声影像系统3D扫描演示装置表面轮廓呈现和3D重建。仿羊水超声影像呈暗回声&#xff08;无回波&#xff09;特性&#xff0c;仿胎儿超声影像呈对比明显…

【附录】Rust国内镜像设置

目录 前言 &#xff08;1&#xff09;设置环境变量 &#xff08;2&#xff09;安装Rust &#xff08;3&#xff09;设置crates镜像 前言 本节课来介绍下如何在国内高速下载安装Rust和Rust依赖&#xff0c;由于网络原因&#xff0c;我们在安装Rust和下载项目依赖时都很慢&am…

【逐行注释】自适应Q和R的AUKF(自适应无迹卡尔曼滤波),附下载链接

文章目录 自适应Q的KF逐行注释的说明运行结果部分代码各模块解释 自适应Q的KF 自适应无迹卡尔曼滤波&#xff08;Adaptive Unscented Kalman Filter&#xff0c;AUKF&#xff09;是一种用于状态估计的滤波算法。它是基于无迹卡尔曼滤波&#xff08;Unscented Kalman Filter&am…

易速鲜花聊天客服机器人的开发(上)

“聊天机器人”项目说明 聊天机器人&#xff08;Chatbot&#xff09;是LLM和LangChain的核心用例之一&#xff0c;很多人学习大语言模型&#xff0c;学习LangChain&#xff0c;就是为了开发出更好的、更能理解用户意图的聊天机器人。聊天机器人的核心特征是&#xff0c;它们可…

ChatGPT/AI辅助网络安全运营之-数据解压缩

在网络安全的世界中&#xff0c;经常会遇到各种压缩的数据&#xff0c;比如zip压缩&#xff0c;比如bzip2压缩&#xff0c;gzip压缩&#xff0c;xz压缩&#xff0c;7z压缩等。网络安全运营中需要对这些不同的压缩数据进行解压缩&#xff0c;解读其本意&#xff0c;本文将探索一…

05_JavaScript注释与常见输出方式

JavaScript注释与常见输出方式 JavaScript注释 源码中注释是不被引擎所解释的&#xff0c;它的作用是对代码进行解释。lavascript 提供两种注释的写法:一种是单行注释&#xff0c;用//起头:另一种是多行注释&#xff0c;放在/*和*/之间。 //这是单行注释/* 这是 多行 注释 *…

网络原理(一):应用层自定义协议的信息组织格式 HTTP 前置知识

目录 1. 应用层 2. 自定义协议 2.1 根据需求 > 明确传输信息 2.2 约定好信息组织的格式 2.2.1 行文本 2.2.2 xml 2.2.3 json 2.2.4 protobuf 3. HTTP 协议 3.1 特点 4. 抓包工具 1. 应用层 在前面的博客中, 我们了解了 TCP/IP 五层协议模型: 应用层传输层网络层…

jvm-45-jvm dump 文件内存介绍+获取+堆内存可视分析化

拓展阅读 JVM FULL GC 生产问题 I-多线程通用实现 JVM FULL GC 生产问题 II-如何定位内存泄露&#xff1f; 线程通用实现 JVM FULL GC 生产问题 III-多线程执行队列的封装实现&#xff0c;进一步抽象 jvm-44-jvm 内存性能分析工具 Eclipse Memory Analyzer Tool (MAT) / 内…

【每天多努力一点】Python编程之元组

和列表类似&#xff0c;元组&#xff08;tuple&#xff09;也是由一系列按特定顺序排列的元素组成的一种复合数据类型。 在某些特定的情境下&#xff0c;元组和列表的区别并没有那么明显。 元组的初始化 元组的基本格式 在Python中&#xff0c;列表通常用小括号&#xff08;…

题目 3209: 蓝桥杯2024年第十五届省赛真题-好数

一个整数如果按从低位到高位的顺序&#xff0c;奇数位&#xff08;个位、百位、万位 &#xff09;上的数字是奇数&#xff0c;偶数位&#xff08;十位、千位、十万位 &#xff09;上的数字是偶数&#xff0c;我们就称之为“好数”。给定一个正整数 N&#xff0c;请计算从…

宠物之家:基于SpringBoot的领养平台

第1章 绪论 1.1 课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。时代进步的标志&#xff0c;就是让人们过上更好的生活。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不…