低成本搭建一台家庭存储服务器:前篇

news2024/12/24 9:12:07

本篇文章,记录搭建备份服务器的过程。

写在前面

今年考虑专门搭建一台用于数据备份的机器,一来今年外出的需求比较多,历史的设备已经用了几年了,需要有更新的设备来“接力”;二来也想验证方案的靠谱程度,解决我接触的一些生产环境的需求以及朋友们的问题。

因为之前已经买过好几台群晖了,加上今年群晖新品的 “CPU 升级” 非常“明智”,于是我决定自建一台。

最终成品

如果不计算硬盘和内存升级,整机连带 UPS 差不多 2000 块,除了能够充当文件服务器之外,还能运行虚拟机和 Docker 容器,相比群晖性价比还是高不少的。

需求明确

我希望这台设备能够满足以下几个诉求:

  1. 必须支持 macOS 系统的数据备份(时间机器),如果能够支持 Windows (生产环境中会有)就更好啦。
  2. 至少有一种靠谱的方案来保障数据写入是正确可靠的。
  3. 系统稳定可靠,三年五载的不需要额外的维护打理。
  4. 体积相对小巧,运行起来没有噪音。
  5. 不包含存储设备(硬盘、内存)成本相对较低,能够支持快速替换硬件来解决可用性问题。

除此之外提供的能力,都是“附加分”。

因为核心诉求其实是软件诉求,所以我们来看看软件方案。

操作系统和软件的选择

我倾向的方案是能够持续稳定运行,不会随意重启的 Linux 系统,或者基于 Linux 系统封装的 NAS 系统,最低的底限是我能够知道“samba”、“afp(netatalk)” 的程序版本,未来能够完成迁移。

本篇文章,我们先使用 Ubuntu 来完成基础的服务搭建。

为什么没有选择“白”或者“黑苹果”

在此之前,我分别使用 Mac 设备,和兼容 Mac 的硬件(包括这台 Elite Desk)运行 macOS,开启文件共享,做了“时间机器”的测试。

相比 Linux 协议兼容的开源软件 netatalk ,确实稳定性高了不少,但是,如果选择使用白苹果,想要限制成本,那么容量就无法满足实际使用;如果选择黑苹果,即使优化配置到 99% 可用,总归觉得还有 1% 的不稳定因素,而我们并不知道这个 1% 的问题什么时候会“触发”,影响有多严重。况且,很有可能不确定性远大于 1%。

为什么没有选择 Windows

因为近几年,我没有主力使用 Windows,对于 Windows 的熟悉程度是不够的。并且,在最近一次的试验中,我发现非服务器版的 Windows 的长时间运行还是有一些问题的(我购入的是专业版的 Licenses)。

11 月末的时候,我入手了一台机器(Dell Optiplex),购入了正版的 Windows 11 ,系统上低负载运行了一款程序。在过去的两个月中,我遇到了跨系统“远程桌面”失效、毫无预兆的“自动”升级和重启,可能作为文件服务器来说,可靠性还需要进一步验证。

硬件方案选择

基于上面的需求,我将硬件选择范围锁定在了 HP EliteDesk 和 Dell Optiplex 两个系列里。经过对比,这次没有选择全新的设备,而是选择了二手市场上供给充沛的 Elite Desk。最终选择了一台 2021 年激活过,因为 2022 “环境变化”退出服役的二手的主机:EliteDesk 800G6 SFF(硬件规格)。

除了机箱有二次喷涂掩盖搬运时的暴力磕碰之外,用酒精擦外壳的时候能够看到喷涂的漆在快速挥发,会有点呛之外,基本没有什么槽点。(不消毒的话,不会触发这个事情,机器本身没气味)

我偷了个懒,选择了搭载 i3-10105T 的机器,成本在 1600 元左右,如果你手头有闲置的 CPU,可以入手 700~800 块左右的准系统。

为什么没有选择新款群晖

我连续购入了前两代的群晖产品 DS918+ 和 DS920+,但是对于 DS 923+,这款“升级到” AMD Ryzen 1600 的产品,实在提不起兴趣。

上文中提到的相对廉价的 i3-10105t CPU 规格可以在 Intel 官网查询到,性价比显然高出不止一头。

为什么没有选择 Apple Time Capsule(时间胶囊)

苹果的时间胶囊

从外观来说,苹果的时间胶囊(技术规格)还是很好看的。但是,产品在 2018 年停产,如果硬件出现问题,通过购置相同硬件来完成服务恢复其实有点麻烦。加上产品即使停产,现在的价格也是小贵的,换起来心疼。

更关键的是,设备只能插一颗磁盘,设备本身算力也非常有限。

为什么没有选择阵列硬盘盒

常见品牌的硬盘阵列盒

如果我们已经有一台设备,并且不介意通过 USB 或者雷电数据线来进行数据交互的话,使用外置阵列硬盘盒未见得不是一个好的方案。这个方案最好的一点是,消费市场中硬盘盒的外观的可选性非常多。

不过,多数硬盘阵列盒不能直接提供服务,需要借助“宿主机”来提供服务,更不能运行一些我们想要运行的软件。而且,既然选择搭建一台设备,并且能够使用更靠谱直连主板的 SATA 线以及更可靠的主机电源,那么硬盘盒的方案的性价比也就不是很高了。何况这类设备的“溢价”非常高。

因为文章开头就“谢绝”了群晖,所以群晖的 “Expansion Unit” 也自然就不在讨论之列了啦。(而且也更贵)

为什么没有选择网络硬盘盒

不论是采用 ARMbian 还是 OpenWRT 的“盒子”,只要硬件靠谱,稳定性都是靠谱的,而且普遍成本低廉,能效比也非常高。

之所以没有选择这个方案,主要的顾虑在硬件可靠性方面,包括三部分:散热、IO能力、供电。

盒子类的设备一般是被动散热,所以如果和硬盘“同处一室”,难以保证有合理的温度,我不想这个备份服务器出现“散装 Style”;盒子类的产品考虑能耗和成本,所以 CPU 相对孱弱,IO 能力自然也就比较弱,跑满硬盘 IO 带宽基本不可能;盒子类的产品供电是带不动多块硬盘的,所以需要独立供电,或者需要和前文提到的能够独立供电的硬盘阵列盒组合使用,容易出现“小马拉大车”的情况。

成品的盒子,几年前我也买过 WD My Cloud 和群晖早些时候的 ARM 产品,就传输效率体验来说,个人体验来说真的不算太好。

准备工作

理论结束,轮到实践啦。

购置配件

我购置了上面这些硬件素材,分别有:

  1. 一台搭载了 CPU 的“准系统”,用于到手后测试“开箱即用”的测试主板和 CPU。
  2. 一台新款的 APC UPS。
  3. 4 根国产的光威 32G DDR4 内存。
  4. 2 块 4T 的西数紫盘,用于数据存储和数据校验。
  5. 一根国产的京造硬盘,用于存放操作系统,以及避免机械硬盘因为有程序运行无法休眠。
  6. 一些配件:数据线和硬盘螺丝。

成本总计 5000 出头,工作功耗 27 瓦左右,总的来说还是比较爽的。当然,你也可以省掉内存升级和固态硬盘的部分,只选购硬件和 UPS ,只需要 2000 出头。

高扩展性的主板

主板的扩展性还不错,默认支持 3 块 SATA 硬盘和 2 块 NVMe 硬盘,4 根内存条,以及两个 PCI-e 插槽。完整的扩展能力,可以阅读上文中提到的“规格资料”。

BIOS 升级

机器到手后,推荐先做两件事,第一件是进入 BIOS ,重置选项为默认选项。第二件则是给机器插上网线,然后使用 BIOS 中的软件升级工具,将 BIOS 升级到最新,避免软件 BUG 和兼容性问题。

BIOS 升级过程

过程中,只有一点注意事项,不要断电,避免造成 BIOS 损坏。

插满内存

考虑到后续想在服务器上运行一些“空间换时间”的程序和虚拟机,我购置了 4 条 32G 的内存,减少分配资源时不必要的“小心翼翼”。

国产内存

插上之后,进入 BIOS ,能够看到正常识别。不过想要确认硬件正常,只是看信息是不够的,还需要进行硬件测试。

BIOS 识别信息

硬件测试

测试硬件需要使用多种方式,如果你的 BIOS 中有测试工具,将能省不少事。

硬件测试

如果你不放心,可以多测试几次,以及使用 PE 或者在完成系统安装之后,使用测试工具进行更持续的测试。

当然,除了一次性测试之外,在使用之前还要进行一些必要的稳定性测试,在实际使用之前,这台设备我通电运行了一周,没有出现意外的异常。

系统的安装和配置

系统待机状态

关于基础的系统安装、配置,可以参考这篇文章《在笔记本上搭建高性价比的 Linux 学习环境:基础篇》。

完成系统安装之后,我们还需要一些额外的配置,来让系统性能表现更好。

禁用 Swap

在 Ubuntu 中完全禁用和清理 Swap 需要三步,首先是关闭 Swap 功能:

sudo swapoff -a

接着,编辑分区表文件 /etc/fstab,去掉 Swap 相关的记录。

然后,重启机器之后,删除掉“残余”文件即可。

rm -rf /swapfile

当你完成上面的动作之后,我们使用 free -g 查看系统资源,就能够看到 Swap 可用量变为零啦:

# free -g
               total        used        free      shared  buff/cache   available
Mem:             125           1         123           0           1         123
Swap:              0           0           0

创建 Raid 1 镜像阵列

先使用 mdadm --examine 来检查机械硬盘的状态,检查两块目标硬盘是否容量一致。

# sudo mdadm --examine /dev/sda /dev/sdb

/dev/sda:
   MBR Magic : aa55
Partition[0] :   4294967295 sectors at            1 (type ee)

/dev/sdb:
   MBR Magic : aa55
Partition[0] :   4294967295 sectors at            1 (type ee)

接着,使用 sgdisk -R 将两个磁盘的分区表进行一致化处理:

sudo sgdisk /dev/sda -R /dev/sdb

复制完分区表之后,需要对其中一个磁盘的分区 UUID 进行刷新,避免操作系统在使用的时候出现问题。

sudo sgdisk /dev/sdb -G

然后,使用 mdadm --create --level=mirror 创建次盘阵列:

# sudo mdadm --create /dev/md0 --level=mirror --raid-devices=2 /dev/sda /dev/sdb

mdadm: /dev/sda appears to be part of a raid array:
       level=raid1 devices=2 ctime=Thu Jan  5 20:47:30 2023
mdadm: partition table exists on /dev/sda but will be lost or
       meaningless after creating array
mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90
mdadm: partition table exists on /dev/sdb
mdadm: partition table exists on /dev/sdb but will be lost or
       meaningless after creating array
Continue creating array? 
Continue creating array? (y/n) y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.

创建磁盘阵列需要等待一些时间,完成时间和你够买的磁盘的容量,以及磁盘和主板的数据传输协议,以及你的设备 CPU 算力都有关系。

我们可以随时通过 cat /proc/mdstat 来检查阵列构建进度:

# cat /proc/mdstat

HP-EliteDesk-800-G6-Small-Form-Factor-PC: Thu Jan  5 21:50:56 2023

Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 sdb[1] sda[0]
      3906886464 blocks super 1.2 [2/2] [UU]
      [=>...................]  resync =  9.6% (375538432/3906886464) finish=325.5min speed=180783K/sec
      bitmap: 28/30 pages [112KB], 65536KB chunk

unused devices: <none>

当阵列构建完成,我们再次检查 mdstat 的时候,能够看到类似下面的日志输出:

# sudo cat /proc/mdstat

Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10] 
md0 : active raid1 sdb[1] sda[0]
      3906886464 blocks super 1.2 [2/2] [UU]
      bitmap: 0/30 pages [0KB], 65536KB chunk

unused devices: <none>

我们也可以使用 mdadm --detail 来查看阵列的详细信息:

# sudo mdadm --detail /dev/md0

/dev/md0:
           Version : 1.2
     Creation Time : Thu Jan  5 21:15:24 2023
        Raid Level : raid1
        Array Size : 3906886464 (3.64 TiB 4.00 TB)
     Used Dev Size : 3906886464 (3.64 TiB 4.00 TB)
      Raid Devices : 2
     Total Devices : 2
       Persistence : Superblock is persistent

     Intent Bitmap : Internal

       Update Time : Fri Jan  6 23:29:38 2023
             State : clean 
    Active Devices : 2
   Working Devices : 2
    Failed Devices : 0
     Spare Devices : 0

Consistency Policy : bitmap

              Name : 0
              UUID : bd87e586:257740d3:5fd50282:ccc8b145
            Events : 6144

    Number   Major   Minor   RaidDevice State
       0       8        0        0      active sync   /dev/sda
       1       8       16        1      active sync   /dev/sdb

中止阵列创建过程

如果你在构建过程中,因为一些原因,想停止构建,可以使用 idle 来中止构建,或者使用 frozen 来临时暂停任务。

echo idle > /sys/block/md0/md/sync_action
echo frozen > /sys/block/md0/md/sync_action

如果你希望完全重新建立阵列,可以使用下面的命令来恢复阵列前的状态:

sudo mdadm -Esv
sudo mdadm --stop /dev/md*

在系统中使用磁盘阵列

完成阵列构建之后,想要使用磁盘阵列,首先得完成磁盘的挂载和磁盘的初始化(格式化)。

# sudo mkfs.ext4 /dev/md0

mke2fs 1.46.5 (30-Dec-2021)
Discarding device blocks: done                            
Creating filesystem with 976721616 4k blocks and 244187136 inodes
Filesystem UUID: f7014dd5-b7b1-466c-ae42-2b49c43cbb57
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
	4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 
	102400000, 214990848, 512000000, 550731776, 644972544

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done   

将磁盘手动挂载到 /data 这个路径,我们可以这样做:

sudo mkdir /data
sudo mount /dev/md0 /data

然后使用 df 来检查磁盘是否就绪:

# df -h /data

Filesystem      Size  Used Avail Use% Mounted on
/dev/md0        3.6T   28K  3.4T   1% /data

实际使用的时候,比如我们在这个分区上创建了一个文件后,磁盘会自动完成文件的镜像动作,提升文件的访问可靠性。

# touch /data/test.go
# sudo mdadm --examine /dev/sda /dev/sdb

/dev/sda:
          Magic : a92b4efc
        Version : 1.2
    Feature Map : 0x1
     Array UUID : bd87e586:257740d3:5fd50282:ccc8b145
           Name : 0
  Creation Time : Thu Jan  5 21:15:24 2023
     Raid Level : raid1
   Raid Devices : 2

 Avail Dev Size : 7813772976 sectors (3.64 TiB 4.00 TB)
     Array Size : 3906886464 KiB (3.64 TiB 4.00 TB)
  Used Dev Size : 7813772928 sectors (3.64 TiB 4.00 TB)
    Data Offset : 264192 sectors
   Super Offset : 8 sectors
   Unused Space : before=264112 sectors, after=48 sectors
          State : clean
    Device UUID : da33683e:54478a8b:cd6fd10e:1a19114c

Internal Bitmap : 8 sectors from superblock
    Update Time : Fri Jan  6 23:29:14 2023
  Bad Block Log : 512 entries available at offset 24 sectors
       Checksum : 5ad089e9 - correct
         Events : 6144


   Device Role : Active device 0
   Array State : AA ('A' == active, '.' == missing, 'R' == replacing)
/dev/sdb:
          Magic : a92b4efc
        Version : 1.2
    Feature Map : 0x1
     Array UUID : bd87e586:257740d3:5fd50282:ccc8b145
           Name : 0
  Creation Time : Thu Jan  5 21:15:24 2023
     Raid Level : raid1
   Raid Devices : 2

 Avail Dev Size : 7813772976 sectors (3.64 TiB 4.00 TB)
     Array Size : 3906886464 KiB (3.64 TiB 4.00 TB)
  Used Dev Size : 7813772928 sectors (3.64 TiB 4.00 TB)
    Data Offset : 264192 sectors
   Super Offset : 8 sectors
   Unused Space : before=264112 sectors, after=48 sectors
          State : clean
    Device UUID : 577ef05f:fa66ff02:8e4085c0:03d798ec

Internal Bitmap : 8 sectors from superblock
    Update Time : Fri Jan  6 23:29:14 2023
  Bad Block Log : 512 entries available at offset 24 sectors
       Checksum : 460982b8 - correct
         Events : 6144


   Device Role : Active device 1
   Array State : AA ('A' == active, '.' == missing, 'R' == replacing)

不过,上面手动挂载的磁盘,如果设备重启,将自动被释放。需要我们再次手动进行设备挂载。

想要解决这个问题,我们需要调整 fstab 中的内容,而 fstab 需要我们先获取阵列的“UUID”,以及更新 mdadm 的配置:

# sudo mdadm --detail --scan --verbose | sudo tee -a /etc/mdadm/mdadm.conf

ARRAY /dev/md0 level=raid1 num-devices=2 metadata=1.2 name=0 UUID=bd87e586:257740d3:5fd50282:ccc8b145
   devices=/dev/sda,/dev/sdb

获取 UUID 需要使用下面的命令,而不能直接使用 mdadm 输出的 ID:

# sudo dumpe2fs /dev/md0 |grep UUID

dumpe2fs 1.46.5 (30-Dec-2021)
Filesystem UUID:          f7014dd5-b7b1-466c-ae42-2b49c43cbb57

然后将下面的内容添加到 /etc/fstab 中:

UUID=f7014dd5-b7b1-466c-ae42-2b49c43cbb57 /dev/md0   /mnt/mirror   ext4   defaults   0   0

搞定之后,更新 initramfs,然后重启设备,检查系统是否能够在启动时,正常挂载阵列分区到 /data 路径即可。

# sudo update-initramfs -u

update-initramfs: Generating /boot/initrd.img-5.15.0-57-generic

安装文件服务

安装文件服务的方案有很多种,比如之前文章《装在笔记本里的私有云环境:网络存储篇(中)》提到的 S3 替代品 MinIO 或者 Syncthing、NextCloud。

不过,为了让 Mac 、Windows 设备能够直接“原生”使用服务,并完成备份,我们可以考虑选择使用 samba 或者 netatalk 提供 smbafp 协议的文件访问能力。如果你希望直接使用本地的 samba 或者 netatalk 程序,直接使用 apt install 即可:

sudo apt-get install samba -y

如果你觉得这样做不够环保,使用 docker 版本的 samba 或者 netatalk 也未尝不可。比如,Stanback/alpine-samba。

当然,用户管理(增加、停用、删除、改密)可能比较麻烦,不过基本都是一次性成本,或许还好。(也可能,再单独展开一篇文章更为合适)

当我们完成服务启动之后,就能够再网络中找到这台“存储服务器”了。

网络服务发现

以及使用 Samba 协议连接服务器。

使用 Samba 访问数据

接下来,如果你愿意的话,就可以直接使用系统自带的“时间机器”,来备份你的设备数据啦。

最后

因为最近比较忙,本篇文章“战线较长”大概经历了两周左右,过程中可能有一些疏漏,如果你有疑问或者建议,欢迎反馈。

下一篇文章中,我们来聊聊如何解决“管理资源”不方便的问题。

–EOF


我们有一个小小的折腾群,里面聚集了一些喜欢折腾的小伙伴。

在不发广告的情况下,我们在里面会一起聊聊软硬件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术沙龙的资料。

喜欢折腾的小伙伴,欢迎阅读下面的内容,扫码添加好友。

  • 关于“交友”的一些建议和看法
  • 添加好友,请备注实名和公司或学校、注明来源和目的,否则不会通过审核。
  • 关于折腾群入群的那些事

本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2023年01月15日
统计字数: 10971字
阅读时间: 22分钟阅读
本文链接: https://soulteary.com/2023/01/15/building-a-home-storage-server-at-low-cost-part-one.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s之ingress实战小栗子

写在前面 本文接k8s之ingress 。 本文看一个基于ingress作为流量入口的实战例子&#xff0c;架构图如下&#xff1a; 接下来详细看下。 1&#xff1a;部署MariaDB 首先我们需要定义MariaDB使用的configmap&#xff0c;如下&#xff1a; apiVersion: v1 kind: ConfigMap meta…

1587_AURIX_TC275_SMU的部分寄存器3

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) SMU的章节&#xff0c;剩下的部分全都是寄存器了&#xff0c;没有太多需要特别关注的。因此&#xff0c;接下来选择性整理&#xff0c;完成整个SMU的文档学习整理。 这一页是上一份笔记的…

05_FreeRTOS中断管理

目录 什么是中断 中断相关寄存器 源码实验 什么是中断 简介:让CPU打断正常运行的程序,转而去处理紧急的事件(程序) ,就叫中断。 举例:上课可以比做CPU正常运行的程序,上厕所可以比做中断程序。 中断执行机制,可简单概括为三步: 中断请求:外设产生中断请求(GPIO外部中断、…

【精品】k8s(Kubernetes)cka由基础到实战学法指南

轻松快速学会k8s四招 图1 k8s四招 学完本篇,您会获得什么惊喜? 从初学k8s,到帮助别人学会的过程中,发现朋友们和我,并非不努力,而是没有掌握更好的方法。有方法可让我们学的更快更轻松,这篇文章,以一个networkpolicy的题目,来逐步讲解,帮助大家建立一种,自己可以根…

Java基础语法

文章目录Java 基础语法一、注释1. 注释介绍2. 注释分类3. 注释颜色二、关键字1. 关键字介绍2. 所有关键词三、字面量四、变量1. 变量2. Debug 工具1&#xff09;如何加断点&#xff1f;2&#xff09;如何开启 Debug 运行&#xff1f;3&#xff09;点哪里 ?4&#xff09;看哪里…

ElasticSearch架构之整合ELK

前言本篇文章主要是说ElasticSearch对Logstash、FileBeat、Kibana整合形成ELK的架构&#xff0c;为什么需要整合这个架构呢&#xff1f;一个很重要的原因就是我们开发过程中有相当多的日志需要进行查看&#xff0c;如果我们要查找一个问题需要到多台服务器进行查看那是相当麻烦…

【Java基础知识 4】Java数据类型之间的转换、运算符

本文已收录专栏 &#x1f332;《Java进阶之路》&#x1f332; 目录 &#x1f334;基本数据类型 &#x1f343;01、布尔 &#x1f343;02、byte &#x1f343;03、short &#x1f343;04、int &#x1f343;05、long &#x1f343;06、float &#x1f343;07、double …

C生万物 | 详解程序环境和预处理【展示程序编译+链接全过程】

&#x1f451;作者主页&#xff1a;Fire_Cloud_1 &#x1f3e0;学习社区&#xff1a;烈火神盾 &#x1f517;专栏链接&#xff1a;万物之源——C 文章目录一、程序的翻译环境和执行环境二、详解编译链接1、前言小知识&#x1f50d;2、翻译环境【important】2.1 编译① 预编译【…

【LeetCode每日一题】【2023/1/15】2293. 极大极小游戏

文章目录2293. 极大极小游戏方法1&#xff1a;双指针2293. 极大极小游戏 LeetCode: 2293. 极大极小游戏 简单\color{#00AF9B}{简单}简单 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#x…

Windows 10的子系统不是非Ubuntu不可

Ubuntu 的制造商 Canonical 早已和微软进行合作&#xff0c;让我们体验了极具争议的 Bash on Windows。外界对此也是褒贬不一&#xff0c;许多 Linux 重度用户则是质疑其是否有用&#xff0c;以及更进一步认为 Bash on Windows 是一个安全隐患。 Unix 的 Bash 是通过 WSL&#…

MyBatis动态设置表名 获取添加功能自增的主键 自定义映射

MyBatis动态设置表名 获取添加功能自增的主键 自定义映射动态设置表名获取添加功能自增的主键自定义映射解决字段名和属性名不一致的情况为字段起别名,保持和属性名的一致设置全局配置,保持和属性名的一致通过resultMap设置自定义的映射关系动态设置表名 mapper接口&#xff1a…

Java实现线段树

问题一&#xff1a;开始的子区间是怎么分的&#xff1f; M (LR)/2&#xff0c;左子区间为[L,M]&#xff0c;右子区间为[M1,R] 问题二&#xff1a;如何进行区间统计&#xff1f; 假设这13个数为1,2,3,4,1,2,3,4,1,2,3,4,1. 在区间之后标上该区间的数字之和&#xff1a; 如…

Windows安全加固-AD建立与加入

AD建立与加入 实验环境说明&#xff1a; 域控从机&#xff1a; Windows 2003 域控主机&#xff1a; Windows 2008 IP设置 设置同一网段-保证连通性 将NDS指向Windos2008 第一步&#xff0c;域控服务器需要将服务器设为静态 IP地址 1.将Windows2008服务器IP地址修改为192.1…

c++ - 第24节 - c++的IO流

1.C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf()与printf()。 scanf(): 从标准输入设备(键盘)读取数据&#xff0c;并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的缓冲区…

【Android gradle】自定义一个android gradle插件之buildSrc

文章目录1. 前言2. 简单使用3. 其余用法3.1 依赖&版本管理3.2 插件版本自增3.3 其余4. 链接1. 前言 在【Android gradle】自定义一个android gradle插件&#xff0c;并发布到私有Artifactory仓库这篇文章中介绍了定义一个gradle插件&#xff0c;然后发布到远程或者本地仓库…

对数据库索引和事务的理解

1.数据库授权命令&#xff1a; GRANT<权限> on 表名(或列名) to 用户。 举例&#xff1a; 授予用户SQLTest对数据库Sales的CUSTOMERS表的列cid、cname的查询权限 grant select on CUSTOMERS(cid,cname) to SQLTest; 2.MySQL索引&#xff08;index&#xff09; 什么是索引…

C++5:初见模板

目录 函数模板 函数模板的实例化&#xff1a; 隐式实例化 显示实例化 类模板 虽然学习了类和对象&#xff0c;能很方便的处理一些容器类的问题&#xff0c;但是我们还是会遇到如下这种情况。 我们创建一个简单的stack类 class Stack { public:Stack(){} private:int* _a;…

【机器学习】Logistic Regression 逻辑回归算法详解 + Java代码实现

文章目录一、逻辑回归简介1.1 什么是逻辑回归1.2 Sigmoid函数1.3 预测函数二、逻辑回归实战 - Java代码实现一、逻辑回归简介 1.1 什么是逻辑回归 逻辑回归&#xff08;Logistic Regression&#xff09;是一种用于解决二分类&#xff08;0 or 1&#xff09;问题的机器学习方法…

时间序列模型SCINet模型(自定义项目)

前言 读完代码解析篇&#xff0c;我们针对开源项目中的模型预测方法做一下介绍。Github源码下载地址下载数据集ETTh、PEMS、Traffic、Splar-Energy、Electricity、Exchange-Rate&#xff0c;这几类公共数据集的任意一类就行。这里以ETTh数据集为例&#xff0c;先在项目文件夹下…

whistle抓包工具应用

原文地址&#xff1a;(67条消息) whistle抓包工具学习_BBC蟹耳总的博客-CSDN博客_w2 抓包 一、安装whistle 首先安装好whistle抓包工具&#xff0c;有以下两个步骤 在终端中全局安装whistle&#xff1a;npm install -g whistle可以通过whistle help查看相关信息&#xff0c;…