✍个人博客:Pandaconda-CSDN博客
📣专栏地址:https://blog.csdn.net/newin2020/category_12903849.html
📚专栏简介:在这个专栏中,我将会分享后端开发面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
1. 简述微服务架构中服务发现的原理和常见实现方式
原理
在微服务架构中,服务数量众多且可能动态变化(如服务的启动、停止、扩容等)。服务发现就是为了解决服务之间如何相互找到对方的问题。其核心原理是:服务提供者在启动时将自己的服务信息(如服务名称、IP 地址、端口号等)注册到服务发现组件中;服务消费者从服务发现组件获取服务提供者的信息,然后根据这些信息去调用服务提供者。这样,服务之间的调用就不需要硬编码服务提供者的地址,而是通过服务发现组件动态获取,提高了系统的灵活性和可维护性。
常见实现方式
- 基于 DNS 的服务发现
- 原理:利用 DNS 系统的解析功能,将服务名称映射到对应的 IP 地址和端口。服务提供者在启动时更新 DNS 记录,服务消费者通过 DNS 查询获取服务提供者的地址。
- 示例:在 Kubernetes 中,可以使用 DNS 服务发现,每个服务都有一个对应的 DNS 名称,其他服务可以通过该名称来访问它。
- 基于注册中心的服务发现
- 原理:使用专门的注册中心组件(如 Eureka、Consul、ZooKeeper 等)。服务提供者在启动时向注册中心注册自己的信息,注册中心维护一个服务注册表;服务消费者从注册中心获取服务提供者的信息。注册中心会定期检查服务的健康状态,移除不健康的服务实例。
- 示例:使用 Eureka 作为注册中心,服务提供者通过 @EnableEurekaClient 注解将自己注册到 Eureka 服务器,服务消费者从 Eureka 服务器获取服务列表并调用服务。
- 基于配置文件的服务发现
- 原理:将服务的地址信息配置在配置文件中,服务启动时读取配置文件获取服务提供者的地址。这种方式适用于服务数量较少且相对稳定的场景。
- 示例:在一些简单的微服务系统中,可以将服务的 IP 地址和端口号配置在 application.properties 或 application.yml 文件中。
2. 在 Python 的 Django 框架中,如何处理文件上传?
步骤
- 配置 settings.py:确保 MEDIA_URL 和 MEDIA_ROOT 已经正确配置。MEDIA_URL 是文件访问的 URL 前缀,MEDIA_ROOT 是文件实际存储的目录。
# settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
- 配置 urls.py:在项目的 urls.py 中添加媒体文件的 URL 映射。
# urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# 其他 URL 配置
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- 创建表单:在 forms.py 中创建一个包含 FileField 或 ImageField 的表单。
# forms.py
from django import forms
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()
- 创建视图:在 views.py 中处理文件上传。
# views.py
from django.shortcuts import render
from .forms import UploadFileForm
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
# 处理上传的文件
title = form.cleaned_data['title']
file = request.FILES['file']
# 保存文件
with open('path/to/save/' + file.name, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
return render(request, 'success.html')
else:
form = UploadFileForm()
return render(request, 'upload.html', {'form': form})
- 创建模板:创建 upload.html 和 success.html 模板文件。
<!-- upload.html -->
<!DOCTYPE html>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">上传</button>
</form>
</body>
</html>
<!-- success.html -->
<!DOCTYPE html>
<html>
<head>
<title>上传成功</title>
</head>
<body>
<h1>文件上传成功!</h1>
</body>
</html>
3. 请解释什么是数据库的死锁,以及如何避免死锁?
死锁的定义
死锁是指两个或多个事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象,导致这些事务都无法继续执行下去。例如,事务 A 持有锁 L1 并请求锁 L2,而事务 B 持有锁 L2 并请求锁 L1,这样两个事务就会陷入无限等待,形成死锁。
避免死锁的方法
按顺序加锁:所有事务按照相同的顺序获取锁,这样可以避免循环等待的情况。例如,在涉及多个表的操作中,所有事务都按照表的字母顺序依次加锁。
减少锁的持有时间:尽量缩短事务持有锁的时间,尽快完成操作并释放锁。可以将一些不必要的操作放在事务外部执行,或者将大事务拆分成多个小事务。
使用锁超时机制:为锁设置一个超时时间,当一个事务等待锁的时间超过该超时时间时,自动放弃锁的请求,避免无限等待。不同的数据库系统提供了不同的锁超时设置方法。
使用事务隔离级别:选择合适的事务隔离级别,避免使用过高的隔离级别,因为高隔离级别可能会增加死锁的概率。例如,在一些场景下可以使用读已提交(Read Committed)隔离级别代替可重复读(Repeatable Read)隔离级别。
检测和回滚:数据库系统可以定期检测死锁的存在,并选择一个事务进行回滚,以打破死锁。回滚的事务通常是造成死锁代价最小的事务。在应用程序中也可以实现死锁检测和重试机制,当检测到死锁时,回滚事务并重新执行。