互联网解决方案-文件存储方案:seafile真实案例

目录

seafile可靠性保证

事件驱动

seafile.log

events.log

事件驱动好处

本地联思文件同步云联思真实案例

本地联思文件同步云联思架构

云联思客户端检查文件API

本地联思访问客户端封装

本地联思队列消费检查

实践过程中的弯路

文件目录处理 move = copy & delete

seafile文件进程占用问题

联思文件生产者-消费者

生产者

消费者


Seafile 是一款开源的企业云盘,注重可靠性和性能,支持全平台客户端。Seafile 内置协同文档 SeaDoc ,让协作撰写、管理和发布文档更便捷。它支持私有化部署,能够满足诸多文件协同的应用场景。


​官网:https://www.seafile.com/home/
国内:https://bbs.seafile.com/
国外:http://forum.seafile.com/

seafile可靠性保证

事件驱动

通过分析seafile的日志发现它是通过事件驱动的。可以通过目录和日志去查看:

seafile.log

[08/05/24 09:36:32] Repo 'mesDir' sync state transition from 'committing' to 'synchronized'.
[08/05/24 09:37:03] Repo 'mesDir' sync state transition from 'initializing' to 'downloading'.
[08/05/24 09:37:03] Transfer repo '9319d653': ('normal', 'init') --> ('normal', 'check')
[08/05/24 09:37:03] Transfer repo '9319d653': ('normal', 'check') --> ('normal', 'commit')
[08/05/24 09:37:03] Transfer repo '9319d653': ('normal', 'commit') --> ('normal', 'fs')
[08/05/24 09:37:03] Transfer repo '9319d653': ('normal', 'fs') --> ('normal', 'data')
[08/05/24 09:37:03] Transfer repo '9319d653': ('normal', 'data') --> ('finished', 'finished')
[08/05/24 09:37:03] Repo 'mesDir' sync state transition from 'downloading' to 'synchronized'.
[08/05/24 09:37:05] Repo 'mesDir' sync state transition from 'synchronized' to 'committing'.
[08/05/24 09:37:05] All events are processed for repo 9319d653-ff60-4cf3-8f59-906697cf0c2d.
[08/05/24 09:37:05] Repo 'mesDir' sync state transition from 'committing' to 'synchronized'.
[08/05/24 09:37:31] Repo 'mesDir' sync state transition from 'synchronized' to 'committing'.
[08/05/24 09:37:31] All events are processed for repo 9319d653-ff60-4cf3-8f59-906697cf0c2d.
[08/05/24 09:37:31] Repo 'mesDir' sync state transition from 'committing' to 'synchronized'.
[08/05/24 09:38:02] [08/05/24 09:38:02] Repo 'mesDir' sync state transition from 'initializing' to 'downloading'.
Transfer repo '9319d653': ('normal', 'init') --> ('normal', 'check')
[08/05/24 09:38:02] Transfer repo '9319d653': ('normal', 'check') --> ('normal', 'commit')
[08/05/24 09:38:02] Transfer repo '9319d653': ('normal', 'commit') --> ('normal', 'fs')
[08/05/24 09:38:02] Transfer repo '9319d653': ('normal', 'fs') --> ('normal', 'data')
[08/05/24 09:38:04] Transfer repo '9319d653': ('normal', 'data') --> ('finished', 'finished')
[08/05/24 09:38:04] Repo 'mesDir' sync state transition from 'downloading' to 'synchronized'.
[08/05/24 09:38:06] Repo 'mesDir' sync state transition from 'synchronized' to 'committing'.
[08/05/24 09:38:06] All events are processed for repo 9319d653-ff60-4cf3-8f59-906697cf0c2d.

events.log

[08/05/24 09:33:05] Starting record seafile events.
[08/05/24 09:42:32] mesDir 9319d653-ff60-4cf3-8f59-906697cf0c2d 98ee680edca112626d1a4db7e961eef5a08457f5
[event 1] delete, attachment/订单Json/2024/8/2024-08-05/e669a2ec-5c06-4f44-a789-ba00f618822e/YYCYJJ240803001YG-13-03.json 
[event 2] delete, attachment/IMOS炸单DWG文件/2024/8/2024-08-05/40a8bc7e-3a5b-48c2-b64c-247c059f9930/YYCYJJ240803001YG-13-03.DWG 
[event 3] delete, attachment/IMOS炸单DWG文件/2024/8/2024-08-05/b5ef8d18-4660-49b9-8907-7235682b5ea0/AJ0SDS022407008YG-10-02.DWG 
[event 4] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031001.mpr 
[event 5] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041001.mpr 
[event 6] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031002.mpr 
[event 7] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041002.mpr 
[event 8] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031003.mpr 
[event 9] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041003.mpr 
[event 10] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031004.mpr 
[event 11] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041004.mpr 
[event 12] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041005.mpr 
[event 13] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031005.mpr 
[event 14] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041006.mpr 
[event 15] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031006.mpr 
[event 16] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041007.mpr 
[event 17] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031007.mpr 
[event 18] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031008.mpr 
[event 19] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041010.mpr 
[event 20] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031009.mpr 
[event 21] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041011.mpr 
[event 22] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031010.mpr 
[event 23] delete, mp4/AJ0SCP012407006YG-08-04/AJ0SCP012407006YG-08-041012.mpr 
[event 24] delete, mp4/AJ0SCP012407006YG-08-03/AJ0SCP012407006YG-08-031011.mpr 

事件驱动好处

逻辑解耦: 不需要关心太多的业务复杂度,只需要在需要的时候发起对应的业务逻辑调用。

时序性保证:通过事件发出就像将处理放入队列一样,能够保证时序性。

可靠性保证:由于事件的时序性很强,从而使数据一致性和可靠性得到保证。

本地联思文件同步云联思真实案例

先介绍下业务背景:由于工业软件的特殊性需要将文件进行不同磁盘目录的合并,通过seafile的同步中转能力实现文件的归档,使得在对外开放的服务器上能够正常访问到文件。

本地联思文件同步云联思架构

架构设计图如下:

 由于seafile上传虽然宣称是可靠的,但是在实际操作中发现并不是百分之百的文件都上去了,还是有掉文件的情况。于是本地联思需要负责检查云联思seafile和云联思目录是否真实存在相应的文件。通过云联思部署客户端对外访问的API接口判定云联思seafile或MES目录是否真实存在上传文件,任意一个目录存在就表示同步完成,当然文件还要校验md5,不是名称一样就表示存在。

云联思客户端检查文件API

云联思客户端提供REST HTTP接口访问,提供心跳接口和相关的校验接口:

@RestController
@RequestMapping("/localMes/productionFiles")
@RequiredArgsConstructor
public class ProductionFileController extends BaseController {

    private final SyncFileMappingConfig syncFileConfig;

    /**
     * 远端请求心跳测试
     *
     * @return
     */
    @GetMapping("/heartbeat")
    public Response<String> heartbeat(HttpServletRequest request) {
        String ipAddress = request.getRemoteAddr();
        String message = String.format("请求心跳:%s %s", ipAddress, DateUtil.formatDate(new Date().getTime(), "yyyy-MM-dd HH:mm:ss.SSS"));
        logger.info(message);
        return onSuccess(message);
    }

    /**
     * 验证路径attachment文件是否存在
     *
     * @param syncFileModel
     * @param bindingResult
     * @return
     */
    @RequestMapping(value = "/attachment/check/exists", method = RequestMethod.POST)
    public Response<SyncFileModel> checkAttachmentPath(@Valid @RequestBody SyncFileModel syncFileModel, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return onBindingInvalidInput(bindingResult);
        }
        markFile(syncFileModel);
        return onSuccess(syncFileModel);
    }

    /**
     * 删除不存在的attachment文件
     *
     * @param syncFileModel
     * @param bindingResult
     * @return
     */
    @RequestMapping(value = "/attachment/delete/notExists", method = RequestMethod.POST)
    public Response<SyncFileModel> deleteAttachmentPath(@Valid @RequestBody SyncFileModel syncFileModel, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return onBindingInvalidInput(bindingResult);
        }
        deleteFile(syncFileModel);
        return onSuccess(syncFileModel);
    }

    /**
     * 验证路径mpr文件是否存在
     *
     * @param syncFileModelList
     * @param bindingResult
     * @return
     */
    @RequestMapping(value = "/mpr/check/exists", method = RequestMethod.POST)
    public Response<SyncFileModelList> checkMprPath(@Valid @RequestBody SyncFileModelList syncFileModelList, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return onBindingInvalidInput(bindingResult);
        }
        for (SyncFileModel syncFileModel : syncFileModelList.getSyncFileModelList()) {
            markFile(syncFileModel);
        }

        // 删除云联思独有的mpr文件
        deleteOnlyOnTargetMprFiles(syncFileModelList);

        return onSuccess(syncFileModelList);
    }

    /**
     * 删除不存在的mpr文件
     *
     * @param syncFileModelList
     * @param bindingResult
     * @return
     */
    @RequestMapping(value = "/mpr/delete/notExists", method = RequestMethod.POST)
    public Response<SyncFileModelList> deleteMprPath(@Valid @RequestBody SyncFileModelList syncFileModelList, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return onBindingInvalidInput(bindingResult);
        }
        if (CollectionUtils.isEmpty(syncFileModelList.getSyncFileModelList())) {
            File file = new File(syncFileConfig.getMappingMp4(), syncFileModelList.getOrderNo());
            if (file.exists()) {
                FileUtil.del(file);
            }
        } el
  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值