Dapr牵手.NET学习笔记:状态管理之docker-compose发布
Dapr牵手.NET学习笔记:想入非非的服务调用
Dapr牵手.NET学习笔记:跨物理机负载均衡服务调用
Dapr牵手.NET学习笔记:用docker-compose部署服务
说明:为了给出demo的全貌,这篇有点长,如果有上一篇的基础,会更容易阅读一些。
在分布式应用,有状态服务是常态,特别是多副本应用,就需要共用缓存来解决数据统一的状况,所以dapr也把状态管理做成一个标准组件。
下面通过docker-compose来发布OrderSystem项目和PaymentSystem项目,他们分别有自己的状态数据,并且测试它们之间的访问性。
下面是项目的目录结构,components文件是dapr组件配置文件夹,B2C是docker-compose的文件夹
OrderSystem项目
HomeController.cs
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Net; using System.Net.Http; using System.Threading.Tasks;namespace OrderSystem.Controllers; [ApiController] [Route("[controller]")] public class HomeController : ControllerBase {private readonly ILogger<HomeController> _logger;private readonly IHttpClientFactory _clientFactory;private readonly string? _payUrl;private readonly string _stateUrl;public HomeController(ILogger<HomeController> logger, IHttpClientFactory clientFactory, IConfiguration configuration){_stateUrl = configuration.GetSection("StateUrl").Value;_payUrl = configuration.GetSection("payurl").Value;_clientFactory = clientFactory;_logger = logger;}[HttpGet("/order")]public async Task<IActionResult> Order(){try{_logger.LogInformation($"下单开始");await Task.Delay(400);_logger.LogInformation($"订单完成 调用支付系统");var client = _clientFactory.CreateClient();var content = await client.GetStringAsync(_payUrl);return new JsonResult(new { order_result = "订单成功", pay_result = content });}catch (Exception exc){_logger.LogCritical(exc, exc.Message);return new JsonResult(new { order_result = "订单成功,支付失败", message = exc.Message });}}[HttpPost("/writekeys")]public async Task<IActionResult> WriteKeys([FromBody] KeyEntity[] keys){var client = _clientFactory.CreateClient();var jsonContent = System.Text.Json.JsonSerializer.Serialize(keys);var content = new StringContent(jsonContent);var response = await client.PostAsync(_stateUrl, content);return Ok(await response.Content.ReadAsStringAsync());}[HttpGet("/readekey/{key}")]public async Task<IActionResult> ReadKey(string key){var client = _clientFactory.CreateClient();var response = await client.GetAsync($"{_stateUrl}/{key}");return new JsonResult(new { key = await response.Content.ReadAsStringAsync(), host = Dns.GetHostName() });}[HttpPost("/readekeys")]public async Task<IActionResult> ReadKeys([FromBody] string[] keys){var client = _clientFactory.CreateClient();var jsonContent = System.Text.Json.JsonSerializer.Serialize(keys);var content = new StringContent(jsonContent);var response = await client.PostAsync($"{_stateUrl}/bulk", content);return Ok(await response.Content.ReadAsStringAsync());}[HttpDelete("/deletekey/{key}")]public async Task<IActionResult> DeleteData(string key){var client = _clientFactory.CreateClient();var response = await client.DeleteAsync($"{_stateUrl}/{key}");return Ok(await response.Content.ReadAsStringAsync());} } public class KeyEntity {public string Key { get; set; }public string Value { get; set; } }appsettings.json
{"Urls": "http://*:80","Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*","PayUrl": "http://localhost:3500/v1.0/invoke/pay/method/pay","StateUrl": "http://localhost:3500/v1.0/state/statestore" }OrderSystem项目的Dockerfile
PaymentSystem项目
HomeControllers.cs与OrderSystem的状态代码是一样的,这里就不占篇幅。
PaymentSystem项目的appsettings.json
{"Urls": "http://*:80","Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*","StateUrl": "http://localhost:3500/v1.0/state/statestore" }PaymentSystem项目的Dockerfile
OrderSystem项目和PaymentSystem项目的Dockerfile中的路径要和docker-compose.yml中的设置有关,所以分享出来,以供参考。
B2C
docker-compose.yml,这里定义了一个b2c-dapr,作为互通网络,打通应用与redis等服务的通道。其中ordersystem对宿主机的端口还是3500,paymentsystem对宿主机的端口分别是3601,3602
Dapr组件配置
statestore.yaml,其中value的值要改成redis,而不是localhost,这里要连接同一个网络里的redis服务
apiVersion: dapr.io/v1alpha1 kind: Component metadata:name: statestore spec:type: state.redisversion: v1metadata:- name: redisHostvalue: redis:6379- name: redisPasswordvalue: ""- name: actorStateStorevalue: "true"启动docker-compose
docker-compose up -d
启动后各服务的状态
测试:
对order服务进行设置状态,这里调用的是dpar服务调用对外的接口,3500是order服务sidecar对外端口。
同理调用order服务的状态数据,返回设置的值
接下来测试从pay服务中调用order服务的状态,返回结果为空,这里的地址为:localhost:3601/v1.0/invoke/pay/method/readekey/USER00001
下面换成从pay1服务的3601中访问order服务的状态,结果有值,url为localhost:3601/v1.0/invoke/order/method/readekey/USER00001,根本原因可能你想到了,这本质上调的还是order服务的接口,只不过是利用pay1的sidecar调用order的sidecar实现的,因为服务调用是通着,所以能调用到,这里可以通过查看返回的host值证明。
接下来测试pay服务,两个副本,访问状态数据的case。下面是通过3601设置状态。
通过pay1的sidecar对外端口访问,url是localhost:3601/v1.0/invoke/pay/method/readekey/PAY00001
通过pay2的sidecar对外端口访问,url是localhost:3602/v1.0/invoke/pay/method/readekey/PAY00001
可见状态数据很好的被隔了,如果跨服务访问状态数据,可以通过服务开放api来实现。
最后看一眼redis数据吧,清晰的展示了服务和数据的关系。
总结
以上是生活随笔为你收集整理的Dapr牵手.NET学习笔记:状态管理之docker-compose发布的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: .NET 6 中的 Configurat
- 下一篇: Dapr + .NET Core实战(三