跳转到内容
彼岸论坛

小天管理

管理员
  • 内容数

    16097
  • 注册日期

  • 最后上线

  • 得奖次数

    1

小天管理 发表的所有内容

  1. 求问大佬们,小弟新买了个 14 寸的 M3 芯片的 MacBook Pro ,要买什么键盘膜,屏幕膜,保护膜比较好啊?磁吸的屏幕膜可以吗?普通的膜是不是会损坏防涂层?
  2. 新闻链接: https://www.zaobao.com.sg/realtime/world/story20240719-4299160 新闻摘要: FBI 无法解锁疑犯的新款三星手机,于是向 Cellebrite 求助。Cellebrite 向 FBI 提供了仍在开发中的新软件,FBI 最终在 40 分钟内破解了手机 声明: 这里只想和大家探讨下技术问题,事件本身不评价
  3. 耳机调到最小的一格了,感觉还是吵。手机可以长按再调小一点,但耳机就没声了。我想应该可以控制输出音量的大小吧?有没有这种 app ?
  4. 为了及时获得提醒,在一台服务器上部署了每分钟访问一次 notifications API 。 前天下午某个时间发现被 cf 挡了,一开始是 525 错误,后来是 500 ,再后来至今一直是 403 。 后来知道是被攻击了。等到昨天再试发现还是 403 ,于是在另一个帖子里反馈了一下。继续等待看能否自动恢复。 又等了些时间后,尝试从我的个人电脑上测试访问 API 能正常进行,但同时在服务器上 curl https://www.v2ex.com 也 403 。至此基本可以肯定服务器 IP 是被 cf 封了... 这明显是被误伤了🤦‍♂️ 不知道后面会自动解除封禁,还是需要通过什么方式反馈解除? @Livid
  5. 感觉 V2EX 的酷工作频道,都是已读乱回的帖子
  6. https://s2.loli.net/2024/07/19/HbXil2LETW9BJKy.jpg 公司的一个内部应用,之前有上架过 App Store ,当时就显示不出来,后来改成了企业证书内部应用,重新安装也还是不显示图标。 已经很多年了,无论是卸载重装、重启 iPad 还是升级系统,依旧都不显示,非常难受。
  7. 今天看到 IT 之家报道了一则新闻:消息称苹果正洽谈购买更多电影版权,以壮大 Apple TV + 片库 我敏锐地意识到了标题中的错误,于是想讲一讲苹果电影商店的一些知识。 首先上结论:标题中的『购买更多电影版权,以壮大 Apple TV+ 片库』是错误的:不是壮大 Apple TV+的片库,而是壮大 Apple TV 平台的电影片库。苹果公司购买的这些电影不会进入 Apple TV+订阅内,而只会进入 Apple TV 的电影片库内。原因是:Apple TV+ 里的电影与电视剧全都是苹果公司自制的,没有例外(如有请告知)。自然地,你订阅了 Apple TV+也看不了这些电影。 当然这不是 IT 之家编辑的责任,因为这涉及到专业知识了。(其实也不专业,只是确实 iTunes 商店的架构有些复杂。只能讲小众吧。) 存在这几个事实: Apple TV+ 相当于 Apple TV 里的一个小专区,是一个比较独立的存在。 因为:Apple TV+ 里的电影与电视剧全都是苹果公司自制的,没有例外(如有请告知)。 Apple TV+ 只提供按月订阅的方案,不提供买断或租借;而 Apple TV 里的电影只提供买断或租借,不提供订阅 (有例外,解释见后文)。 接下来,我把不同专区里的电影在 Apple TV 软件里的主页截图放上来,大家立马就明白怎么回事了(注意看每部电影提供哪些观看方式)。截图是拼接截图,自上而下是: 《盗梦空间》。属于 Apple TV ,不属于 Apple TV+。老早就在电影片库里,不是苹果公司最近买来的版权; 《花式舞蹈》。属于 Apple TV+,不属于 Apple TV ,苹果公司出品; 《贱女孩》 《泰坦尼克号》 后两部电影就是本新闻中提到的,苹果公司最近才买来的电影版权。它们属于 Apple TV ,不属于 Apple TV+(同时,前文所述的例外也在此) 大家看截图就能发现,苹果公司才购买来版权的这两部电影,无法通过订阅 Apple TV+ 来观看。除了买断与租借外,还可以通过订阅『 Paramont+』的方式来看(比 Apple TV+贵一点点)。可见,苹果公司是买了派拉蒙影业公司的版权。 本人在流媒体平台、投屏方案等小众领域有一定调研,所以懂一些。 另外关于 Apple TV 与 iTunes Store 这两个名字,我的理解是:iTunes Store 里卖电影、音乐、铃声等各种东西,那么 Apple TV 就相当于把 iTunes Store 里的电影单独拿出来做了一个 App 。其实这些电影在 Apple TV 跟 iTunes Store 里都能看到。好比苹果公司刚出了古典音乐版 Apple Music ,那么一首古典音乐在以下三个 App 里都能听到:『 Apple Music 古典乐』『 Apple Music 』『 iTunes Store 』 只不过 Apple TV+这个专门卖苹果公司自制内容的平台,只能在 Apple TV 这一个 app 里看到,也许是苹果公司想要打造 Apple TV 这个品牌吧。 号外:最新发现:iTunes Store 里买不了电影了: 所以苹果公司的媒体商店是不是特别复杂?
  8. 亲戚家孩子今年高考,男孩,文科。高考分数差 1 本线 2 分。现在选专业和学校比较发愁,文科可选项实在太少。v2 群里基本上都是理工科的吧,大家对文科选专业有什么建议的,反正我感觉二本里面随便选都不知道哪个专业是好专业。
  9. 前段时间给老爸买了个红米 k70e,到手我尽量把广告和推送关闭了,模式也调整为长辈模式,现在有个问题,老爸使用过程中不知道点了什么,过几天手机就会安装几个软件,目前可以确认时小米商店下载安装的软件,手机没有其他应用商店,浏览器下载安装就更不可能了(小米手机安装第三方软件的操作逻辑老人也不会弄,况且也需要输入小米账户密码,老爸不知道密码),感觉应该是还有推送广告或者其他推广误点击后静默下载安装,把小米手机应用商店禁止自启,禁止后台,禁用网络,但是打开应用商店仍能下载软件,小米手机有没有类似 ios 的机制,安装软件需要验证下
  10. 早上看到短信提醒,进邮箱看了一下,把密码重置了
  11. 最近公司要安装两套监控,不知道大家都是在哪找的方案。我们在海康威视京东自营店买了上门勘测服务,过来现场后给了下面的方案,也不知道合不合理,个人感觉有点贵。
  12. 昨天看到“iOS 类似李跳跳的软件”,提到 quantumult X 、墨鱼、懒人配置 可以分流屏蔽广告,就搞了软件,安装配置。 现在能到外网,一直是通过小火箭或者 clash ,加载机场的配置文件。 问题: 1.圈 X 的分流规则与小火箭的的规则,是不是存在冲突,那我应该怎么去配置呢。 2.圈 X 与小火箭可以同时运行吗? 3.实现翻墙和屏蔽广告,还有什么,我可以了解和掌握的。
  13. 1x 年前 iphone4 流行的时候用过 2 年苹果,后面一直用安卓,前年又心血来潮再次用了下苹果,感觉有些操作不是很方便,于是今年又换回安卓了 但是换了才发现网易云音乐还没去取消自动 vip 续费,结果去取消才发现苹果这取消操作也是各种反人类 苹果给我妈用了,所以手头暂时没苹果手机 之前是通过支付宝绑定的自动续费,去支付宝,提示我必须去苹果上取消 又去网易云音乐安卓 app ,还是提示要去苹果 app 取消 ok 到这我也能理解,毕竟涉及到跨国业务 登录苹果 id 后台,到处都找不到能管理续费的地方,我一头郁闷 google 搜索终于找到个写着取消自动续费的链接,点击,提示我必须在 itunes 上操作。。。 目前的状况就是我为了取消一个自动续费-本来只需要点下鼠标就能操作的小事,还得去借一个苹果手机来,或者安装 itunes-甚至我都不知道安装后能不能成功取消 如果苹果有提供了网页版自动续费管理的话,我作为一个熟练玩转互联网+it 开发工程师用户都不能在半小时内找到这入口,我认为是极其极其失败的,对小白来说只会更难 一点点小事,让我对苹果仅剩不多的一点点好感更加雪上加霜
  14. RT 申请收录到 VXNA 系统,因为是国内服务器,故没有申请域名仅用公网 ip ,谢谢版主
  15. 程序员自由创业周记#38:让画画更简单 拥抱 AIGC 在之前,如果想得到一张想要的图片,通常有几个选择: 在图片资源网站,搜索关键词,找到类似的图片,充会员下载。(不能指定风格) 找一名插画师,按照你的想法单独为你创作。(贵) 如果自己学过设计,耗费半天自己画一张符合自己要求的图... (难) 而现在,AI 时代,只需要一句指令,即能生成任意风格无版权的精美图片。 而高质量的 AI 软件,使用起来,对我们并没有那么友好,比如需要爬梯子; 而且价格也是让人望而却步: 普通人使用有一定难度,为了让每个人能更低成本高质量的拥抱 AIGC ,我做了一个 AI 画图软件,直接 AppStore 下载使用,不需要爬梯子,用的国内最好的画图大模型之一,价格是上面一个产品的 2%。 而且不需要付费前提下,每个人可以生成 9 张无版权 AI 图片,完全按照自己的指令,自己想要的风格,使用的 Token 我来买单。 这个软件使用的客户端原生技术 SwiftUI ,会同时支持 iOS 、iPad 、Mac 三个平台和 iCloud 全平台同步。 值得一提的是,目前版本的低价不会持续很久。 支持的风格和使用场景 发朋友圈想找一张合适的配图 插画 PPT 、文案配图 红薯或者博客文章配图&封面 独一无二的个性壁纸 头像 生成图片的质量 如何体验 AppStore 搜索:AI 画图王 或者在 Safari 输入:https://apps.apple.com/app/6505048186 本周进展 上线创业做的这第五个软件:AI 画图王 日常维护:Island Widgets-学伟®灵动岛锁屏小组件 陪孩子 打球 学英语:每天群打卡 看话剧:《乌龙..》 读书:《小而美》 听播客 学做饭 往期文章: 创业周记合集
  16. 如题,还有,新 UI 体验如何?
  17. 前几天突然感觉人生苦短,想出去走走,就微信最铁的朋友,咱们去看黄土高坡吧,不谋而合,于是各自购买了机票,今天就飞西安。。。
  18. 115 网盘官网每次关闭浏览器的时候都得重新登录 谁有没有脚本或者是浏览器插件推荐推荐
  19. 教育优惠好像开始了 ,各位大佬带价来吧,
  20.   很多数据库使用者都觉得分布式数据库这个大家伙安装麻烦、配置要求高、需要大量资源。我们花了十几年的时间,从零开始写了一个叫做 OceanBase 的 “单机分布式一体化” 纯自研数据库,已经经历过支付宝和淘宝多年双十一极端业务场景的验证,在这里推荐给大家。   OceanBase 社区版本代码开源,兼容 MySQL 的语法和功能,存储成本只有 MySQL 的四分之一到六分之一。既支持个人用户在 2C 6G 的小规格的单机环境下使用,也支持水平动态扩展成分布式的部署模式。 🍎 项目仓库地址   OceanBase 是开源的分布式数据库,仓库地址是: https://github.com/oceanbase/oceanbase   欢迎对数据库感兴趣的朋友们在 github 上关注我们的开源项目,也欢迎将大家对 OceanBase 的任何问题在 github 的项目中提出 issue ,我们会及时跟进大家的 issue 并对问题进行解答。 🌰 单机分布式一体化   帖子标题里提到了一个大家比较陌生的词汇“单机分布式一体化”,那究竟什么是单机分布式一体化?以及单机分布式一体化解决了数据库使用过程中的什么问题?   对于很多的企业,都有一个从小到大的过程,在业务从小到大的过程中,很多厂商采用的方案往往是这样子的: 一开始因为数据量比较小,用的往往是一台小规格的机器,然后部署一个 MySQL ; 当数据量变大的时候,可能会选择去换成 Oracle ; 如果业务量再持续变大,单机 Oracle 也支撑不了,需要一定的扩展性,那就会用 Oracle 的 RAC 或者对 MySQL 分库分表。但是大家知道,Oracle RAC 的扩展性是非常有限的,当 RAC 的节点数量达到十几个的时候,他再往上加节点性能就很难提升了,MySQL 分库分表更是有诸多使用上的限制以及中间件的单点瓶颈问题。 那实在不行,后面可能会选择一些小型机配上 db2 。   这样的路径存在很大的问题,一个是扩展性仍然是有天花板的,并不是能无限扩展的。第二个问题是,在业务量变大的过程中,每做一次数据库的重新选型和架构的调整,对上层的业务来说,都是一次翻天覆地的变化。   OceanBase 就是想给大家提供一条更加简单的路线,我们在底层把数据库的扩展性做好,让上层业务可以专注于自己的业务研发。   OceanBase 从单机部署变更到分布式部署的过程中: 可以选择类似于 MySQL 的主备库架构; 如果用户考虑主备库 RPO 不为 0 ,可能因为有延时带来丢数据的问题,那可以从主备库动态升级到 1-1-1 三副本的高可用模式; 如果用户觉得主备库、三副本这些东西掌握起来比较复杂,那么也可以继续使用单机模式,因为 OceanBase 在单机模式下也具有非常好的垂直扩展能力。 如果业务规模继续增长,比如从一个中型的业务变成了一个大型,甚至超大型的业务,可以把 1-1-1 这种三 zone 三节点的部署模式(每个 zone 中都会有一份完整的数据副本),进一步扩展成最右边这种 2-2-2 甚至 n-n-n 的部署模式。当然 zone 的数量不限于 3 个,也可以继续扩展,比如对于支付宝这种对高可用要求非常高的超大型的业务,蚂蚁主站用的部署模式是三地五中心,也就是有五个 zone ,五份副本。   当业务量持续增长,部署方式从单机向分布式进行变更时,因为 OceanBase 是原生的分布式数据库,所以可以完全消除传统单机数据库分库分表带来的各种痛点和使用上的限制。无论是垂直扩展,增加单机规格,还是水平扩展,增加集群内的节点数量,都不需要停机停服,对上层业务无感。用户可以自始至终都无须关心底层数据库选型上的变化。 🍑 快速上手   OceanBase 社区版的语法和功能完全兼容 MySQL ,存储成本却只有 MySQL 的四分之一,还支持水平扩展,在不同的部署方式之间进行灵活的变化。   大家可以参考 https://open.oceanbase.com/quickStart 中的 “使用 obd demo 命令快速部署 OceanBase 数据库” 部分,只需要在 linux 环境下执行以下几条命令,即可快速体验 OceanBase 数据库(单机版)。 # 若您的机器可以连接网络,可执行如下命令在线下载并安装 all-in-one 安装包。 bash -c "$(curl -s https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/download-center/opensource/oceanbase-all-in-one/installer.sh)" source ~/.oceanbase-all-in-one/bin/env.sh # 执行以下命令,快速部署 OceanBase 数据库。 obd demo # 使用 OBClient 客户端连接到 OceanBase 数据库。 # 通过 2881 端口直连数据库。 obclient -h127.0.0.1 -P2881 -uroot@sys -Doceanbase -A # 通过 ODP 代理访问数据库。 obclient -h127.0.0.1 -P2883 -uroot@sys -Doceanbase -A   大家如果对 OceanBase 有任何疑问,或者在 OceanBase 的使用过程中遇到任何问题,都可以在我们的社区论坛 https://ask.oceanbase.com/ 中发帖进行提问,会有专业的技术同学对大家的问题及时进行解答。   最后附上一个 OceanBase 官网文档的地址: https://www.oceanbase.com/docs/oceanbase-database-cn 供大家对 OceanBase 相关资料进行查阅。
  21. 请问各位大佬,这种网络卡顿的状况如何排查原因 问题描述 最近租房的网络一直不稳定,具体表现为:正在看 B 站直播,经常性的出现卡顿的情况。然后就 ping 了一下网络状况, 窗口一(从左到右):ping www.bing.com -t,这是 ping 外部网络的。 窗口二:ping 192.168.1.1 -t,这个应该是 ping 光猫地址的。 窗口三:ping 192.168.16.1 -t,这个是我屋子里的路由器地址的。 https://i.imgur.com/EyvGmQL.png 网络结构大概是:房东拉的光纤接光猫,再接交换机,然后我们各户自己的路由器再接到交换机上。 具体情况是:经常性的出现卡顿,表现为:不能访问外部网络,但是过了十几秒之后,又能正常访问。当出现网络卡顿的时候(访问不了外部网络),ping www.bing.com -t 返回的是无法访问目标主机,但是ping 192.168.1.1和ping 192.168.16.1 是能一直 ping 通的。 还有一个情况是:当能正常访问外部网络的时候,浏览器访问地址 192.168.1.1 是光猫登录页面,但是当网络不能正常访问的时候,返回的登录页面不知道是哪个设备的。 https://i.imgur.com/decJGzr.png https://i.imgur.com/OOSYU21.png 请问各位大佬,这种情况下大概是什么原因呢?是硬件设备还是配置的原因,具体应该怎么排查呢?
  22. 大概是从四年级还是五年级做自己的项目开始,感觉好像就隐隐约约有倾向想要在 commit 里面写越来越多东西。一开始只是写比如从哪个 Stackoverflow 讨论串找到的参考资料,后来到一些算法或者设计上的东西,然后发现自己的 commit 标题越来越长,感觉长过头了就写进了 message 里面,然后就在 message 里面写 markdown 了。 上班后感觉好像这个倾向又被强化了,一方面摸鱼写的代码的 commit 很容易一个 commit 里面覆盖多个内容,而不是像写自己的项目那样细粒度到一两个文件,另一方面又总是担心意图没解释清楚别人难以理解自己的代码。 所以 commit 有时候就会长这样: ```markdown [Core] (fix) Sorting algorithm, XXX Page, YYY Service - Designed an algorithm to sort a certain dataset according to some requirements and constraints - Included this algorithm into XXX page - Extracted several methods to YYY service - Removed deprecated codes - Added test suite for subjects mentioned above The algorithm scans the incoming dataset, which should conform to ..., at a first pass, it will ... Some code has been refactored and reformatted. ``` 不过也不总是这么长就是,如果 commit 改变的东西不多的话,那倒是经常一两个 bullet 就完了。 另外也感觉发 PR 的时候好像我总喜欢写得像 GitHub 的 readme 一样。 不过也听说是不是说长 commit 是新手的普遍操作,senior 的 commit 普遍一句话带过。
  23. ✨官方公告 OpenAI 最新推出 GPT-4o mini 模型,小而巧! 新模型目前在聊天偏好上表现优于 GPT-4 模型,并在大规模多任务语言理解( MMLU )测试中获得了 82%的得分。 价格方面,GPT-4o mini 的成本为每百万输入 Token 为 0.15 美元、每百万输出 Token 为 0.6 美元,比 GPT-3.5 Turbo 便宜超过 60%。 官方介绍: https://openai.com/index/gpt-4o-mini-advancing-cost-efficient-intelligence/ 注意:OpenKey.Cloud 平台将于近期开始评估并适配。
  24. 如何实现异步通知的重试机制 工作中经常要和第三方做对接,比如支付、电子合同等系统。操作成功之后,第三方会发送异步的通知,返回最终的处理结果,使用异步而不是使用同步通知,是为了加快系统响应速度,防止线程阻塞。任务处理完成后通过异步的通知,发送给对应的服务端。之前对接微信支付,完成支付后,微信发送一个异步通知给服务端,服务端根据支付通知修改状态,通知规则看到以下的一段话。 其中有段话: 重新发送通知,直到成功为止(在通知一直不成功的情况下,微信总共会发起多次通知,通知频率为 15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m ) 微信为何要这么设计 微信结果通知本质就是发送一个网络请求到不同的服务器上,既然是一个网络请求,就可能因为各种原因导致请求超时或者失败,比如: 请求的服务器挂了 网络发生了波动 服务器响应异常 以上原因都会导致支付结果通知接收失败,也就无法通知给用户。为了解决上述的问题,就需要引入重试机制,当请求无法应答时,就需要重试几次,保证请求能确认发送。 异步通知的重试机制 从微信支付通知可以引申到所有的异步通知,或者和第三方对接时。如果要确保通知能被成功的接收,就需要考虑请求失败的情况,大部分都是需要使用重试机制。而重试机制是隔段时间不是固定的,是越来越大的,这是考虑到重试时,由于网络故障或者服务器故障重启设备需要花一段时间,而间隔时间越来越长就可以更大的保证请求可以被成功接收。 重复请求,接口需要考虑重复请求的情况,要设计成一个幂等性接口,多次请求和请求一次的效果是一致的。 重试机制的实现 重试机制就是一个定时器,隔一段时间执行一次,没有预期的效果就再重复执行一次。 实现的难点就在于,间隔的时间是不一致的,如果时间的间隔是固定的话,就可以使用定时任务。 方案一:定时任务(不可行) 使用定时器,每隔一段时间执行一次任务。在 SpringBoot 启动类添加 @EnableScheduling 注解,然后在执行的方法添加 @Scheduled 注解。 @Scheduled(fixedDelay = 1000*2) public void test2() { Date date = new Date(); System.out.println("tesk2 " + date); } 以上表示每隔 2 秒执行一次。间隔时间都是固定的,这个不符合预期,因为要求的时间间隔是依次增加的。 如果是间隔时间是固定的,那定时任务就符合条件吗? 如果是只有一条任务在执行,执行不成功,存放在 Redis 中,然后定时执行任务,如果任务执行成功,就去掉任务。但是定时器还是会定时执行。 如果执行的任务很多的话,前面的任务要等待后续的任务执行,那延迟就很严重了,就需要使用到多线程,开启多个线程,在《阿里 Java 开发手册》有一条: 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 定时任务有以下几个缺点不满足: 时间间隔固定。 只能单线程处理任务,任务越多,延迟性越久。 方案二:线程池 + 定时任务 (不可行) 既然使用单线程会产生延迟,就使用线程池来降低延迟,因为发起请求属于 IO 密集型,所以线程数设置成 CPU 个数的两倍,在 SpringBoot 自定义一个线程池: @Configuration public class ThreadPoolConfig { // 线程存活时间 private static int keepAliveTime = 10; // 调用线程运行多余任务 RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); @Bean("customerTaskExecutor") public TaskExecutor taskExecutor() { // 核心线程数 int cores = Runtime.getRuntime().availableProcessors()*2; ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(cores); executor.setMaxPoolSize(cores); executor.setKeepAliveSeconds(keepAliveTime); executor.setRejectedExecutionHandler(handler); executor.setThreadNamePrefix("Custom-"); // 线程名前缀 executor.initialize(); return executor; } } 其中核心线程数和最大线程数设置成一致,拒绝策略使用调用线程运行多余的任务,确保每个任务都能执行。然后添加一个异步方法. public interface AsyncService { void executeAsync(); } @Service @Slf4j public class AsyncServiceImpl implements AsyncService { @Override @Async("customerTaskExecutor") public void executeAsync() { log.info(" [开始执行任务] "); // 延迟几秒 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } log.info(" [结束执行任务] "); } } 使用 sleep 方法延迟,模拟请求,使用压测工具,发起 100 次请求,控制台输出如下: 2023-10-31 18:00:32.792 INFO 53009 --- [ Custom-1] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.811 INFO 53009 --- [ Custom-2] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.813 INFO 53009 --- [ Custom-3] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.814 INFO 53009 --- [ Custom-4] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.816 INFO 53009 --- [ Custom-5] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.817 INFO 53009 --- [ Custom-6] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.819 INFO 53009 --- [ Custom-7] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.820 INFO 53009 --- [ Custom-8] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.821 INFO 53009 --- [ Custom-9] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.823 INFO 53009 --- [ Custom-10] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.824 INFO 53009 --- [ Custom-11] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:32.825 INFO 53009 --- [ Custom-12] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 2023-10-31 18:00:33.296 INFO 53009 --- [ Custom-1] com.jeremy.threadpool.AsyncServiceImpl : [结束执行任务] 2023-10-31 18:00:33.296 INFO 53009 --- [ Custom-1] com.jeremy.threadpool.AsyncServiceImpl : [开始执行任务] 采用线程池执行的任务,多个线程同时执行任务,能有效的降低了任务的延迟性。定时任务间隔固定时间从数据库 Mysql 或者 Redis 获取需要请求的数据,同时执行请求。 这样就有几个问题: 间隔是固定的。 空闲的时候没有请求执行,到了执行时间,大量的请求在执行,导致闲的时候闲死,忙的时候忙死。资源得不到很好的利用。 除了定时器,还有什么组件可以解决上面问题,那就是使用消息中间件了。 方案三:消息中间件 + 线程池(可行) 使用线程池的方式开启多个线程运行。那针对固定时间间隔和只能同时执行的问题使用消息中间件就能很好的解决问题,消息中间件采用生产+消费模型实现消息的生产和消费, 延迟队列 本文使用消息中间件 RabbitMQ 实现延迟队列,具体实现可以看我的另外一篇文章延迟队列实现订单超时自动取消,具体实现流程图试下如下。 请求发送失败之后,调用生产者发送消息,经过设定的时间间隔之后,发送给消费者,消费端再次发起请求,如果请求失败,再调用生产者发送消息,并设置好下一次的时间间隔,其中消费端发起任务使用线程池发起请求。 下载 RabbitMQ 延迟消息的插件 delayed_message_exchange , 在Github 官网找到对应的版本,我选择的是 3.8.17: 配置延迟队列: @Configuration public class XDelayedMessageConfig { /** * 延迟交换机 */ public static final String DELAYED_EXCHANGE = "exchange.delayed"; /** * 重试队列 */ public static final String RETRY_QUEUE = "queue.retry"; /** * 重试 routing key */ public static final String RETRY_ROUTING_KEY = "routingKey.bind.retry"; @Bean public Queue retryQueue() { return new Queue(RETRY_QUEUE,true); } /** * 定义延迟交换机 * 交换机的类型为 x-delayed-message * @return */ @Bean public CustomExchange delayedExchange() { Map<String,Object> map = new HashMap<>(); map.put("x-delayed-type","direct"); return new CustomExchange(DELAYED_EXCHANGE,"x-delayed-message",true,false,map); } @Bean public Binding retryQueueBinding() { return BindingBuilder.bind(retryQueue()).to(delayedExchange()).with(RETRY_ROUTING_KEY).noargs(); } } 在发送端模拟重试机制,设置时间间隔 5 、10 、30 秒。 @Autowired private RabbitTemplate rabbitTemplate; private final int[] INTERVAL_ARRAY= {5,10,30}; @GetMapping("/retry") public String retry(int index) { if (index >= 0 && index <= 2) { send(index +",延迟" + INTERVAL_ARRAY[index] + "s",INTERVAL_ARRAY[index]); } return "ok"; } private void send(String message,Integer delayTime) { message = message + " " + DateUtil.dateFormat(new Date()); System.out.println(" [发送消息] " + message); rabbitTemplate.convertAndSend(XDelayedMessageConfig.DELAYED_EXCHANGE,XDelayedMessageConfig.RETRY_ROUTING_KEY, message, message1 -> { message1.getMessageProperties().setDelay(delayTime*1000); return message1; }); } 接收端: @RabbitListener(queues = XDelayedMessageConfig.RETRY_QUEUE) public void delayProcess(String msg, Channel channel, Message message) { System.out.println(" [接收消息] " + msg + " 当前时间" + DateUtil.dateFormat(new Date())); try { channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); } catch (IOException e) { e.printStackTrace(); } int index = Integer.parseInt(msg.split(",")[0]); retry(++index); } 控制台输出: [发送消息] 0,延迟 5s 10:59:29 [接收消息] 0,延迟 5s 10:59:29 当前时间 10:59:33 [发送消息] 1,延迟 10s 10:59:33 [接收消息] 1,延迟 10s 10:59:33 当前时间 10:59:43 [发送消息] 2,延迟 30s 10:59:43 [接收消息] 2,延迟 30s 10:59:43 当前时间 11:00:10 其中 0 、1 、2 表示重试的次数。通过延迟消息的方式,重试发送信息。每个任务作为一个消息进行消费。和定时服务相比,有以下几个优点: 支持动态间隔 任务不是同时执行,降低服务器的压力。 总结 在发送一些异步通知时候,需要考虑到通知可能接收失败的情况,比如: 请求的服务器挂了。 网络发生了波动。 服务器响应异常,服务重启。 此时无法正确的及时推送通知,无法保证通知的可靠性。这个时候就需要重试多次,而且间隔要依次增加,因为服务启动或者网络的卡顿在经过一段时间就恢复了。后续重试成功的概率就更高了。 定时重试 定时重试首先不符合变化的间隔时间,间隔的时间是固定的,重试的任务都堆积在一起请求,这样也会给服务器造成很大的压力。而空闲的时候,服务器的利用率有比较低。 同时请求,只能一个一个同步执行任务,同时执行的任务越多,延迟就越严重。 定时任务 + 线程池 为了解决同时处理任务,添加了自定义的线程池,因为请求属于 IO 密集型,所以设置线程数为 CPU 核数的两倍。 多个任务执行,降低了延迟性。 无法满足动态间隔时间的问题,而且同时请求服务器压力大。 延迟队列 + 线程池 延迟时间请求可以使用到延迟队列,每个任务都作为一个消息。每次处理不成功,就发送消息到延迟队列中,到达时间间隔之后,再消费消息。如果请求失败再重复以上操作。 消费者处理消息,使用线程池处理,加快处理速度。也可以开启多台服务器分发处理任务,加快处理速度,降低任务的延迟性。 如果感觉写的不错的,欢迎关注我的公众号
×
×
  • 创建新的...