.NET 5 设计 API (资源站)
跟新于 2022-11日
数据抓取端
随着数据的增多,问题也越来越多
用redis 主要是为了 以后进行,多个数据库写入。
例如我搭建一个 别的数据库论坛,我直接拿数据去redis里面拿,就不用跨库查询然后,加载到内存里面,以此类推 (比如我现在存的hash 是一个月度数据,和每日新增的数据 和修改的数据,这样我就可以直接传递不同参数写入不同数据库只需要定义 pipline 方法即可,不需要再查一下 在循环!)
问题点:
1、每天日常抓取数据写入的时候,之前没有处理Href链接,导致要查询一次富文本内容,去提取Href,(查一个月度的数据,特别卡,花费要五十多秒)
2、限流问题,之前被别人Doss攻击了导致服务器停止了一个月(我的服务器是轻量云的 每月只有1T多一点)。
3、爬虫挂了没有通知,之前爬虫挂了一个多星期我没有发现,数据没跟新一周,直接亏了!
新增需求
1、(打算对接一个stmp 邮件服务,不过好像服务器端口不支持,暂定把,邮箱服务通知-Net)
2、现在写入task 任务是使用写入task表,完成一个任务就去修改task表中的 State 状态,少量数据还可以,数据多了,或者多开几个线程,就有问题了(直接数据库顶不住了,当然我这个数据库,装在服务器上,一大把服务都在上面 性能有限)
解决方案:
日常数据增量问题
解决
1、开始用了一个比较呆的方法,使用SQL INSERT INTO SELET 语句去 写入一个新表(只需要字段,标题、Href、Id),最近发现这样去执行,效率不是很理想,如果后续数据累加,速度上比较慢
最近突然想到一个方法,使用 redis
使用Hset 进行存每日Insert 写入的数据 和 Update 的数据,这样就不用每次去删表,
实际使用效果非常好,(之前我写好了一个RabbitMQ的生产和消费,打算用定时任务每日去巡检,新增的然后写入到MQ中,然后专门写个消费者,定时去pull消费,我发现太大材小用了,就好比拿着 大刀去削个苹果,=-=)
解决效果
可以看到Redis 写入成功 这里我扩展了 post的序列化 和反序 操作,注意(因为抓取的数据来自不同的网站,可能会存在重复的数据 Id,我这里处理的方法是我这边生成的一个Base64加密 把数据Id + 抓取的网站Url路由 生成一个 HashId) 但是最近发现有的网站会换域名,如果发现不及时,导致还是有很小的部分重复,(这个重复暂时没想到解决办法!)
缓存预加载任务
使用 BackgroundService + IMediator
首先我们要声明一个 返回IMedator 进行注入
点击查看代码
public class TaskCacheService : BackgroundService
{
private readonly ILogger<TaskCacheService> _logger;
private readonly IServiceProvider _provider;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Delay(1000, stoppingToken);
RecurringJob.AddOrUpdate(() => RedisCache(), Cron.Daily(1));
throw new System.NotImplementedException();
}
/// <summary>
/// 写入redis 任务
/// </summary>
/// <returns></returns>
public async Task RedisCache()
{
await GetMediator().Send(new PostRedisRequest { StartTime = DateTime.Now.AddDays(-1).Date });
}
private IMediator GetMediator()
{
return _provider.CreateScope().ServiceProvider.GetService<IMediator>();
}
}
大概现在有 19W 条数据,
(后面使用go的框架 重写了一版 )
使用的 框架(go_spider) ==> https://gitee.com/huhuzhu/go_spider
go_spider =(这个功能很多用不到我自己取消了 部分功能)
ORM使用的是(Confluence) ==> https://goframe.org/pages/viewpage.action?pageId=1114245
另外使用了一个 第三方的http 库 http.Client ==> https://gitee.com/guonaihong/gout
前台使用的vue --> vue(大部分别人帮我写的,比如组件封装之类的,接口什么的是我自己调的)
http://xh.bozaiq.cn/ 每天早晨6点会更新一批数据
API后端
后台使用 net5 + ef core (开始是想代码实现读写分离,发现数据太少了 看不到效果,后面在慢慢爬取一点)
部署在docker 中,(第一次尝试部署在docker中踩了很多坑)
使用的ef core 框架
因为加入了 一个访问日志 ==》 https://www.bozaiq.cn/d/100-logmiddleware 感觉第一次加载特别慢
本来想用redis 缓存前十页,用redis存储List的话还需要进行jsonConvert 序列化 和反序列化操作,
我就用的微软推荐的 Microsoft.Extensions.Caching.Memory ==>https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/memory?view=aspnetcore-6.0
使用redis缓存了文章详情页,因为是收集网上的基本上是不会改动这个文章页 默认缓存(标识字段,IsCache = true)
swagger 地址 http://xh.bozaiq.cn:8084/swagger/index.html (jwt登陆 =》 todo - 权限管理)
这里Controller 用的是 using MediatR 个包
中介者(Mediator)模式:用一个中介对象来封装一系列的对象交互,中介者使各个对象不需要显示的相互引用,从而使得耦合松散,而且可以独立的改变他们之间的交互
可以看到Controller 是非常明了的只需要定义请求和返回 (abpNET5)
具体的功能实现 自己定义一个 Handler文件夹
这里的PagedAsync() 这个是自己扩展的一个静态的方法 意思就是 分页并异步(因为框架比较模块设计 每个模块都可以根据需求自己扩展)
CancellationToken 这里 对长时间阻塞调用的异步取消令牌应用,在某些场景中,我们需要请求外部的第三方资源,但是由于网络等原因,可能会造成长时间的等待以致业务超时退出,这种情况可以使用 CancellationToken 来进行优化,但请求超过指定时长后退出,而不必针对每个 HttpClient 进行单独的超时设置
CancellationToken 一般.netCore 它和取消异步任务相关的 可以参考:https://www.cnblogs.com/fanfan-90/p/12660996.html
线上的total 我给屏蔽了,实际是每天会自动跟新一批数据 每天自动抓取大概几千条左右
加入了 限流中间件和显示PageSize 大小,防止爬虫
点击查看代码
``` C#
public class HomeHandler : IRequestHandler>
{
private readonly IRepository _postsRepository;
private readonly IRepository _disRepository;
private readonly IMapper _mapper;
public HomeHandler(IRepository<Posts, int> postsRepository, IRepository<Discussions, int> disRepository, IMapper mapper)
{
_postsRepository = postsRepository;
_disRepository = disRepository;
_mapper = mapper;
}
public async Task<PagedResultDto<GetPostItem>> Handle(GetPostRequest request, CancellationToken cancellationToken)
{
// 查询条件
var postquery = _postsRepository.GetQuery();
var disquery = _disRepository.GetQuery();
var queries = from post in postquery
join dis in disquery
on (int)post.DiscussionId equals dis.Id
select new GetPostItem
{
Id = post.Id,
Type = post.Type,
Content = post.Content,
Title = dis.Title,
CreateOn = post.CreateOn,
UpdateOn = post.UpdateOn
};
var query = queries.WhereIf(!string.IsNullOrEmpty(request.Keyworks), a => a.Title.Contains(request.Keyworks) || a.Content.Contains(request.Keyworks));
//查询数据库
var items = await query.PagedAsync(request);
var total = await query.CountAsync();
var pageTotal = items.Count();
return new PagedResultDto<GetPostItem>(items, total, pageTotal);
}
}
/// <summary>
/// 请求类型
/// </summary>
public class GetPostRequest : PagedRequest, IRequest<PagedResultDto<GetPostItem>>
{
public string Keyworks { get; set; }
}
/// <summary>
/// 返回类型
/// </summary>
public class GetPostItem : EntityDto<int>
{
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 类型
/// </summary>
public string Type { get; set; }
/// <summary>
/// 内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 状态:-1-删除 0-禁用 1-正常
/// </summary>
public EntityStatusEnums Status { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreateOn { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdateOn { get; set; }
}
</details>
#### EFCore --> sql控制台日志
```C#
public static readonly ILoggerFactory MyLogFactory = LoggerFactory.Create(build =>
{
build.AddConsole(); // 用于控制台程序的输出
// build.AddDebug(); // 用于VS调试,输出窗口的输出
});
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLoggerFactory(MyLogFactory);
}
.NET 5 设计 API (资源站)的更多相关文章
- 8个设计师必看的免费UI图标设计资源站
图标是我们日常APP及网页设计过程中必不可少的元素之一,通过小小的图标,可以快速方便的实现视觉引导和功能划分.在创作时,我们需要寻找各种各样的图标来满足自己的设计需求,非常浪费时间和精力.今天,小编给 ...
- 海洋cms自带资源发布api插件和第三方资源站接入办法说明
海洋cms自带资源发布api插件和第三方资源站接入办法说明 时间:2016-07-15 13:46 来源:CMS模版网 作者:大宇 阅读:7095次 ===海洋cms自带API资源发布插件说明===* ...
- 14.app后端如何设计api
app和后端的交互,一般都是通过后端提供的api实现.api的设计,估计很多刚进入app后端的小伙伴会一无头绪,不知道怎么入门.下面根据自己3年的app后端经验,总结出下几个api设计原则,给小伙伴参 ...
- 微服务设计 - api版本控制
要描述了几种API版本控制的方法.用户可以查询原始的API,或者添加定制的头文件来接收特定的版本.如果应用程序收到一个重大修订,将URI修改为V2.在进行迭代改进时,将创建与更改日期相一致的端点,并允 ...
- 好的框架需要好的 API 设计 —— API 设计的六个原则
说到框架设计,打心底都会觉得很大很宽泛,而 API 设计是框架设计中的重要组成部分.相比于有很多大佬都认可的面向对象的六大原则.23 种常见的设计模式来说,API 设计确实缺少行业公认的原则或者说设计 ...
- flask插件系列之flask_restful设计API
前言 flask框架默认的路由和视图函数映射规则是通过在视图函数上直接添加路由装饰器来实现的,这使得路由和视图函数的对应关系变得清晰,但对于统一的API开发就变得不怎么美妙了,尤其是当路由接口足够多的 ...
- Atitit.自定义存储引擎的接口设计 api 标准化 attilax 总结 mysql
Atitit.自定义存储引擎的接口设计 api 标准化 attilax 总结 mysql 1. 图16.1:MySQL体系结构1 2. 16.7. 创建表create()虚拟函数:2 3. 16.8 ...
- 3- vue django restful framework 打造生鲜超市 - model设计和资源导入
3- vue django restful framework 打造生鲜超市 - model设计和资源导入 使用Python3.6与Django2.0.2(Django-rest-framework) ...
- API 资源隔离系统设计与实现
(马蜂窝技术原创内容,公众号 ID:mfwtech) Part 1 背景 大交通业务需要对接机票.火车票.租车.接送机等业务的外部供应链,供应商的数据接口大部分通过 HTTP.HTTPS 等协议进行通 ...
随机推荐
- JavaWeb--HTTP与Maven
前言 Java Web 其实就是一个技术的总和,把Web看成一个容器而已主要使用JavaEE技术来实现.在加上各种中间件. 整个javaWeb阶段的内容通过实际的案例贯穿学习, 所涉及到的技术知识点会 ...
- 网站加了CDN后,字体图标报错Access-Control-Allow-Origin
这两天将自己做的网站(PM老猫)上线了,上线后发现因为之前购买的服务器带宽较小,第一次打开网站页面就会比较慢,想着给网站加了个CDN,让静态文件直接通过CDN访问.网上一找发现可以白嫖的CDN服务挺多 ...
- 如何应对外包公司(文思海辉)的Python后端面试
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_151 最近春招如火如荼,我接触到的几位同学也纷纷去市场里试了试水,不得不说由于疫情的影响,导致目前中等水平的开发者择业有了些许困难 ...
- Docker容器网络配置
Docker容器网络配置 1.Linux内核实现名称空间的创建 1.1 ip netns命令 可以借助ip netns命令来完成对 Network Namespace 的各种操作.ip netns命令 ...
- 我与Apache DolphinScheduler的成长之路
关于 Apache DolphinScheduler社区 Apache DolphinScheduler(incubator) 于17年在易观数科立项,19年3月开源, 19 年8月进入Apache ...
- ENSP 与VMware workstation 同时安装会出现AR40 或者VMware蓝屏
前言: 你已经安装了VMware workstation,ENSP,Virtualbox,并且关闭了hyper-v,还会出现报错或者VMware蓝屏. #此处补充一条命令systeminfo 如果你看 ...
- 【Java】学习路径52-Timer计时器实例
import java.util.Timer; import java.util.TimerTask; public class TimerClass { public static void mai ...
- 「题解报告」P2154 虔诚的墓主人
P2154 虔诚的墓主人 题解 原题传送门 题意 在 \(n\times m\) 一个方格上给你 \(w\) 个点,求方格里每个点正上下左右各选 \(k\) 个点的方案数. \(1 \le N, M ...
- JavaScript之数组常用API
这篇文章主要帮助大家简单理解数组的一些常用API用法,许多小伙伴常用方法记不住?别急,看完下面的介绍您一定就会明白各个方法是如何用的了.该文章适合新手小白看,大佬可以多多指点️! 1.数组的创建以及A ...
- mocha、chai和supertest单元测试
mocha单元测试 1. 因为有时候在代码中加了新的东西需要反复测试接口 或者 别人要求 重新跑接口非常的繁琐 2. 所有我们需要一个帮我们重复测试的东西 那就是mocha 3. 先下载 一定不要全 ...