C#与.NET技术
实践与教程

专注分享C#、ASP.NET Core、Azure、Blazor等微软技术栈的开发教程、架构设计和最佳实践

85
技术文章
42
教程系列
2.8k
月访问量
328
活跃读者
分布式系统并发控制:从单机锁到分布式锁的深度解析
后端
2024-05-06 0k

分布式系统并发控制:从单机锁到分布式锁的深度解析

引言 在分布式系统开发中,并发控制是一个永恒的话题。最近在代码评审时,我看到了这样一段代码: // 复杂操作仍需 lock public void ComplexOperation() { lock (_lockObj) { if (_count > 0 && _count < 100) { _count *= 2; // 其他复杂业务逻辑... } } } 这引发了一系列深入的讨论:如果锁里面执行的是用户下单操作,A用户下单过程中执行了1秒,B用户的请求会怎样?是直接失败还是等待?我们需要手动处理这种等待吗? 本文将围绕这个问题展开,深入探讨单机锁、细粒度锁、数据库事务和Redis分布式锁的优缺点及适用场景。 第一部分:单机锁的行为分析 锁的基本行为 当我们在C#中使用lock语句时,CLR会为我们管理一个等待队列: public void PlaceOrder(Order order) { lock (_lockObj) // 所有用户下单都串行化! { // 复杂的下单逻辑,耗时1秒... ProcessOrder(order); UpdateInventory(); // 其他业务... } } 关键结论:B用户会等待A用户执行完,而不是直接失败。整个过程是自动的,不需要人工干预。 具体执行流程 A用户进入lock块,开始执行下单操作(耗时1秒) B用户的线程到达lock语句时,发现_lockObj已被锁定 B线程会阻塞并等待,直到A线程释放锁 A用户执行完毕,释放锁 B线程获得锁,开始执行自己的下单操作 单机锁的严重问题 虽然锁机制自动处理了同步,但这种设计存在严重问题: 性能瓶颈:所有用户请求串行处理 响应时间变长:B用户需要等待A用户的1秒 + 自己的1秒 = 至少2秒 系统吞吐量下降:无法充分利用多核CPU优势 第二部分:解决方案对比 🥉 方案一:细粒度锁 private readonly Dictionary<string, object> _userLocks = new(); private readonly object _dictLock = new object(); public void PlaceOrder(string userId, Order order) { object userLock; lock (_dictLock) { if (!

分布式系统 并发控制 锁机制
阅读更多
从JSONP到CORS:跨域解决方案的技术演进与架构思考
前端
2024-02-12 0k

从JSONP到CORS:跨域解决方案的技术演进与架构思考

在Web开发领域,CORS(跨源资源共享)是每个前端开发者都会遇到的关键概念。但为什么我们如今使用CORS,而曾经流行的JSONP却逐渐退出历史舞台?本文将带您深入理解跨域解决方案从JSONP到CORS的技术演进历程。 第一部分:理解CORS - 跨域资源共享 什么是CORS? CORS(Cross-Origin Resource Sharing,跨源资源共享)是浏览器强制执行的一种安全机制,用于解决"同源策略"带来的限制。 同源策略要求协议、域名、端口完全相同的请求才被允许。例如: https://www.example.com → https://api.example.com ❌ 跨域 http://localhost:3000 → http://localhost:8080 ❌ 跨域 CORS的工作原理 当浏览器检测到跨域请求时,会执行以下流程: 发送预检请求:对于非简单请求,浏览器先发送OPTIONS请求 服务器响应:后端返回包含CORS头部的响应 浏览器验证:浏览器检查头部,决定是否放行 实际请求:验证通过后发送真正的请求 # 预检请求 OPTIONS /api/data HTTP/1.1 Origin: https://www.example.com Access-Control-Request-Method: POST # 服务器响应 HTTP/1.1 200 OK Access-Control-Allow-Origin: https://www.example.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: Content-Type 为什么配置服务端CORS就能解决问题? 关键在于:CORS的决定权在服务器,浏览器只是执行者。 当您在.NET服务端配置CORS时,有多种方式: ASP.NET Core 全局配置: // Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOrigin", policy => { policy.

CORS JSONP 跨域
阅读更多
DDD领域驱动设计全面解析:.NET核心概念与落地实践指南
后端
2024-01-24 0k

DDD领域驱动设计全面解析:.NET核心概念与落地实践指南

DDD领域驱动设计全面解析:.NET核心概念与落地实践指南 领域驱动设计(Domain-Driven Design,简称 DDD)是一种以业务领域为核心的现代化软件架构设计方法论,专注于解决复杂企业级业务系统的设计与开发难题。在当今微服务架构和分布式系统盛行的环境下,DDD已成为构建高内聚、低耦合系统的最佳实践。本文将深入剖析DDD核心概念,结合.NET技术栈全面讲解DDD落地实践,帮助开发者掌握企业级应用架构设计精髓。 .NET 作为成熟稳定的企业级开发平台,天然支持 DDD 领域驱动设计的核心诉求 —— 无论是分层架构、面向对象设计,还是依赖注入、领域模型映射等,都能通过 ASP.NET Core、EF Core、MediatR 等 .NET 生态工具无缝落地。本文将从 DDD 领域驱动设计的核心思想出发,结合 .NET 实战场景,系统讲解 DDD 关键概念、架构分层及落地技巧,提供完整的企业应用架构解决方案。 一、DDD领域驱动设计核心思想:业务驱动的架构哲学 DDD领域驱动设计的本质是业务驱动而非技术驱动,所有设计决策都围绕业务需求展开,在 .NET 企业应用开发中,核心遵循三大原则: 领域优先:业务逻辑(领域模型)是系统的核心资产,技术细节(数据库、API、缓存等)仅作为辅助实现; 边界清晰:通过「限界上下文」划分业务边界,解决复杂系统中的 “知识混乱”,避免不同业务模块的概念冲突; 迭代演进:通过「领域语言(Ubiquitous Language)」统一团队(开发、产品、测试)认知,领域模型随业务迭代持续优化。 二、DDD核心概念详解与.NET落地实践 DDD 的概念体系可分为「领域层核心概念」「架构分层」「辅助概念」三类,以下结合 .NET 代码示例和生态工具逐一说明。 (一)领域层核心概念:DDD业务逻辑的核心载体 领域层是 DDD 的 “心脏”,包含业务模型、规则和行为,不依赖任何外部技术框架,纯业务逻辑封装。 1. 领域模型(Domain Model)- DDD核心设计元素 领域模型是业务概念的代码映射,分为两种设计风格: 贫血模型:仅包含属性和 getter/setter,无业务逻辑(传统 MVC 常用,非 DDD 推荐); 充血模型:包含属性 + 业务逻辑方法(DDD 核心),模型自身封装业务规则,确保数据一致性。 .

DDD 领域驱动设计 dotnet
阅读更多
天气查询API实现 | 后端开发最佳实践
后端
2023-12-25 0k

天气查询API实现 | 后端开发最佳实践

1. 天气查询功能介绍 天气查询API在现代Web和移动应用中扮演着重要角色,它可以为用户提供实时天气数据、未来天气预报以及生活指数等关键信息。本文将详细介绍如何实现一个高效、稳定的天气查询服务,涵盖从API选择、异步编程实现到缓存优化的完整开发流程。 2. 天气API服务选择指南 在开发天气查询应用时,选择合适的API服务提供商至关重要。以下是几个主流的天气API服务对比: 和风天气API:国内数据覆盖全面,API文档完善,适合后端开发使用 OpenWeatherMap:全球天气数据服务,国际化支持好 高德地图天气API:国内覆盖较全面,适合本地化应用 百度地图天气API:与百度地图集成良好,适合地图应用场景 本文以和风天气API为例,详细讲解调用天气API的完整实现方案,包括API密钥获取、请求构建、响应解析和错误处理等关键环节。 3. 天气查询API代码实现 3.1 获取和风天气API密钥 在开始天气查询开发前,首先需要在和风天气开发者平台注册账号并获取API密钥。注册流程简单,完成后即可获得免费额度的API访问权限。 3.2 天气查询类实现 using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; public class WeatherAPI { private readonly string _apiKey; private readonly string _baseUrl; private readonly HttpClient _httpClient; public WeatherAPI(string apiKey) { _apiKey = apiKey; _baseUrl = "https://devapi.qweather.com/v7"; _httpClient = new HttpClient(); _httpClient.Timeout = TimeSpan.FromSeconds(10); } /// <summary> /// 实现获取指定位置的实时天气数据 /// 支持城市ID或经纬度查询 /// </summary> public async Task<Dictionary<string, object>> GetCurrentWeatherAsync(string location) { string url = $"{_baseUrl}/weather/now"; var parameters = new Dictionary<string, string> { { "key", _apiKey }, { "location", location } // 可以是城市ID或经纬度 }; try { using (var response = await _httpClient.

C#天气查询 ASP.NET Core开发 和风天气API调用
阅读更多
jQuery给编译后页面中vue变量赋值
2022-04-14 0k

jQuery给编译后页面中vue变量赋值

要赋值的input框 <input tabindex="1" type="text" autocomplete="off" placeholder="AppID" name="appId" class="el-input__inner"> 通过name获取对象赋值 $("input[name='appId']").val("24563574-04f5-4a44-848e-84ea81677e34"); 赋值后没有效果,需要触发vue事件 $("input[name='appId']")[0].dispatchEvent(new Event('input'))

JQ vue jQuery
阅读更多
压力测试工具jmeter安装使用
软件测试
2021-11-26 0k

压力测试工具jmeter安装使用

一、安装jmeter jmeter3.3以上要匹配8.0以上jdk,所以安装前需要先安装JDK。 JDK下载地址: https://www.oracle.com/java/technologies/downloads/#java8-windows 安装后在CMD窗口输入java -version,出现版本号即安装成功。 jmeter下载地址: http://jmeter.apache.org/download_jmeter.cgi 配置环境变量: #添加JMETER_HOME,路径就是jmeter保存的位置 JMETER_HOME=D:\Program Files\apache-jmeter-5.4.1 #添加CLASSPATH CLASSPATH=%JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;%JMETER_HOME%\lib\jorphan.jar; #修改path,在后面添加 %JMETER_HOME%\bin cmd窗口输入jmeter运行或者双击bin目录下jmeter.bat 二、使用jmeter 1、新建线程组 在计划右键–新建线程组 如果默认没有计划, 点击菜单种文件–新建计划 线程组控制面板: 线程数:您正在测试的用户数 加速时间:您希望允许线程组从0到N个用户的时间 循环计数:应该循环测试的次数 调度器:测试持续时间,启动延迟时间 2、新建http请求 在线程组右键–添加–取样器–http请求 post json 请求 json数据放到消息体数据中 自定义请求头,在HTTP请求右键–添加–配置原件–HTTP信息头管理器 3、查看结果 线程组–添加–监听器–[察看结果数 / 汇总报告 / 聚合报告]

jmeter 测试
阅读更多
Nginx的基本使用
2021-11-18 0k

Nginx的基本使用

什么是Nginx? Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。 反向代理 Nginx 根据接收到的请求的端口,域名,url,将请求转发给不同的机器,不同的端口(或直接返回结果),然后将返回的数据返回给客户端。 安装Nginx #如果缺少依赖,先安装依赖 yum -y install gcc gcc-c++ openssl openssl-devel #下载 wget http://nginx.org/download/nginx-1.20.1.tar.gz #进入服务安装包目录,这里放到了home/server cd /home/server/ #解压tar包 tar -zxvf nginx-1.20.1.tar.gz #进入解压nginx目录 cd nginx-1.20.1 #执行configure进行配置,这里配置可以根据自己项目需要进行自定义配置 ./configure --prefix=/usr/local/nginx --with-http_ssl_module #执行安装 make && make install Nginx配置参数中文详细说明 #定义Nginx运行的用户和用户组 user www www; # #nginx进程数,建议设置为等于CPU总核心数. worker_processes 8; # #全局错误日志定义类型,[ debug | info | notice | warn | error | crit ] error_log /var/log/nginx/error.log info; # #进程文件 pid /var/run/nginx.pid; # #一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致.

nginx 中间件 服务器
阅读更多
linux系统常用基础命令
2021-11-15 0k

linux系统常用基础命令

目录操作 #当前目录 pwd # 创建目录 mkdir $HOME/testFolder #切换目录 cd $HOME/testFolder #切换到上一级目录 cd ../ # 移动 mv $HOME/testFolder /var/tmp #删除 rm -rf /var/tmp/testFolder #查看目录下的文件 # /etc 目录默认是 Unix 系统的软件配置文件存放位置 ls /etc #竖着显示查询结果 ls -l / #查看所有目录包括子目录(效果很酷) ls -R / 文件操作 #创建 touch ~/testFile #复制 cp ~/testFile ~/testNewFile #删除 rm ~/testFile #查找名称包含nginx的.conf文件 find / -name '*.conf' |grep nginx #解压: # tar.gz tar tgz tar xzvf FileName.tar.gz #压缩: tar czvf FileName.tar.gz DirName 查看文件 #一、从第3000行开始,显示1000行。即显示3000~3999行 cat filename | tail -n +3000 | head -n 1000 #二、显示1000行到3000行 cat filename| head -n 3000 | tail -n +1000 #----------------------------- #注意两种方法的顺序 # 分解: # tail -n 1000:显示最后1000行 # tail -n +1000:从1000行开始显示,显示1000行以后的 # head -n 1000:显示前面1000行 #-------------------------------- #三、用sed命令 sed -n '5,10p' filename 这样就可以只查看文件的第5行到第10行。 #过滤出 /etc/passwd 文件中包含 root 的记录 grep 'root' /etc/passwd #递归地过滤出 /var/log/ 目录中包含 linux 的记录 grep -r 'linux' /var/log/ #重定向 #可以使用 > 或 < 将命令的输出到一个文件中 echo 'Hello World' > ~/test.

阿里云 流水线 云效Flow 实现持续集成、持续部署(CI/CD)
2021-09-22 0k

阿里云 流水线 云效Flow 实现持续集成、持续部署(CI/CD)

新建流水线 选择对应语言,新建流水线 选择代码源 这个代码我托管在云效自带的Codeup 代码结构 设置代码源触发 开启代码源触发,并添加Webhook,Codeup会带动添加,如果是码云、github等其他托管平台,需要手动将下面webhook地址添加到代码托管平台对应的Webhook 配置构建 配置部署 新建主机,部署项目的服务器,如果是集群可以添加多台 如果账号内有阿里云ECS直接选择即可,否则选自有服务器,复制脚本在目标服务器执行 添加部署脚本和变量 脚本 $image变量是配置的镜像仓库地址,在上游构建时,会将构建好的docker镜像推送到这个地址 echo $image #停止正在运行的容器 docker stop apidemo #删除容器 docker rm apidemo #拉取容器 docker pull $image #运行新容器 docker run -d -p 1080:80 --name apidemo $image 完成自动构建、部署 提交代码触发流水线 云效2020文档地址:https://help.aliyun.com/product/150040.html 云效Flow地址:https://flow.aliyun.com/ 云效地址:https://devops.aliyun.com/

dotnet DevOps Linux
阅读更多
jenkins实现dotnet项目持续集成、持续部署(CI/CD)
2021-09-21 0k

jenkins实现dotnet项目持续集成、持续部署(CI/CD)

添加节点 这个jenkins是用docker安装的,我们要操作宿主机构建项目,不是这个容器,所以要把这个容器本身的节点停止,添加宿主机节点 断开jenkins容器节点 Master 也可以使用标签限制 新建节点 添加宿主机连接信息 添加宿主机认证用户 生成ssh公钥和私钥 执行:ssh-keygen 一路回车 进入.ssh文件夹: cd .ssh/ id_rsa:私钥 id_rsa.pub:公钥 把公钥写到authorized_keys文件: cat id_rsa.pub > authorized_keys 复制私钥到jenkins cat id_rsa 添加触发器 token可以区分项目 把地址复制到代码托管平台,设置触发 添加构建脚本 Jenkins构建完成会自动关闭进程及其子进程,造成nohup 无效,需要在命令内加参数BUILD_ID=DONTKILLME publish.sh: #!/bin/bash #如果8081被占用杀掉进程 kill -9 $(lsof -i:8081 -t) cd /home/web/web-demo/ #拉代码 git pull #发布代码到publish目录 dotnet publish -o publish cd publish/ #后台启用项目,端口8081 nohup dotnet WebDemo.dll --urls http://0.0.0.0:8081 & 构建记录

dotnet CentOS Linux
阅读更多