跟新于 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 条数据,

gitee地址 : https://gitee.com/Lovely_Rabbit/pan_web-api.git

(后面使用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 (资源站)的更多相关文章

  1. 8个设计师必看的免费UI图标设计资源站

    图标是我们日常APP及网页设计过程中必不可少的元素之一,通过小小的图标,可以快速方便的实现视觉引导和功能划分.在创作时,我们需要寻找各种各样的图标来满足自己的设计需求,非常浪费时间和精力.今天,小编给 ...

  2. 海洋cms自带资源发布api插件和第三方资源站接入办法说明

    海洋cms自带资源发布api插件和第三方资源站接入办法说明 时间:2016-07-15 13:46 来源:CMS模版网 作者:大宇 阅读:7095次 ===海洋cms自带API资源发布插件说明===* ...

  3. 14.app后端如何设计api

    app和后端的交互,一般都是通过后端提供的api实现.api的设计,估计很多刚进入app后端的小伙伴会一无头绪,不知道怎么入门.下面根据自己3年的app后端经验,总结出下几个api设计原则,给小伙伴参 ...

  4. 微服务设计 - api版本控制

    要描述了几种API版本控制的方法.用户可以查询原始的API,或者添加定制的头文件来接收特定的版本.如果应用程序收到一个重大修订,将URI修改为V2.在进行迭代改进时,将创建与更改日期相一致的端点,并允 ...

  5. 好的框架需要好的 API 设计 —— API 设计的六个原则

    说到框架设计,打心底都会觉得很大很宽泛,而 API 设计是框架设计中的重要组成部分.相比于有很多大佬都认可的面向对象的六大原则.23 种常见的设计模式来说,API 设计确实缺少行业公认的原则或者说设计 ...

  6. flask插件系列之flask_restful设计API

    前言 flask框架默认的路由和视图函数映射规则是通过在视图函数上直接添加路由装饰器来实现的,这使得路由和视图函数的对应关系变得清晰,但对于统一的API开发就变得不怎么美妙了,尤其是当路由接口足够多的 ...

  7. Atitit.自定义存储引擎的接口设计 api 标准化 attilax 总结  mysql

    Atitit.自定义存储引擎的接口设计 api 标准化 attilax 总结  mysql 1. 图16.1:MySQL体系结构1 2. 16.7. 创建表create()虚拟函数:2 3. 16.8 ...

  8. 3- vue django restful framework 打造生鲜超市 - model设计和资源导入

    3- vue django restful framework 打造生鲜超市 - model设计和资源导入 使用Python3.6与Django2.0.2(Django-rest-framework) ...

  9. API 资源隔离系统设计与实现

    (马蜂窝技术原创内容,公众号 ID:mfwtech) Part 1 背景 大交通业务需要对接机票.火车票.租车.接送机等业务的外部供应链,供应商的数据接口大部分通过 HTTP.HTTPS 等协议进行通 ...

随机推荐

  1. DateFormat类的format方法和parse方法

    /** * 使用DateFormat类中的方法format,把日期格式化为文本 * String format(Date date) 按照指定的模式把Date日期格式化为符合模式的字符串 * 使用步骤 ...

  2. 万答#13,MySQL自增键用完后,插入数据会发生什么情况

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 MySQL自增键用完了,插入数据会发生什么情况 1.实验场景 GreatSQL ...

  3. Spherical类定义和实现

    此类是一个全景摄像机视角,书上介绍了详细原理.直接给实现代码. 类声明: #pragma once #ifndef __SPHERICAL_HEADER__ #define __SPHERICAL_H ...

  4. JAVA语言基础组成(2)

    函数  函数的定义 1.什么是函数? 函数就是定义在类中的具有特定功能的一段独立小程序.函数也称为方法. 2.函数的格式: 修饰符 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,.. ...

  5. 感谢有你!Apache DolphinScheduler 项目 GitHub star 突破 8k

    本周伊始,Apache DolphinScheduler 项目在 GitHub 上的 Github Star 总数首次突破 8K.目前,Apache DolphinScheduler 社区已经拥有 C ...

  6. 制作离线yum源

    互联网上操作 1.安装所需依赖环境和软件包 1.1安装命令 yum install yum-utils createrepo 1.2各软件包功能 createrepo :生成yum 源各软件之间的依赖 ...

  7. P4675 [BalticOI 2016 day1]Park (并查集)

    题面 在 Byteland 的首都,有一个以围墙包裹的矩形公园,其中以圆形表示游客和树. 公园里有四个入口,分别在四个角落( 1 , 2 , 3 , 4 1, 2, 3, 4 1,2,3,4 分别对应 ...

  8. grep使用常用操作十五条

    grep的全部使用语法参照grep --help,日常工作常用的语法如下:构造数据如下:test001.txt与test002.txt 一.在单个文件中查询指定字符串 grep abc test01/ ...

  9. KingbaseES时间函数的比较

    KingbaseES提供了多种的时间函数,这些函数在使用过程中存在哪些不同? **同一事务** test=# begin test-# for i in 1.. 10 loop test-# rais ...

  10. 使用 Spring Boot Admin 监控应用状态

    程序员优雅哥 SpringBoot 2.7 实战基础 - 11 - 使用 Spring Boot Admin 监控应用状态 1 Spring Boot Actuator Spring Boot Act ...