Doris-ansible自动化部署脚本

包结构

暂时无法在飞书文档外展示此内容

perl 复制代码
doris_ansible
├── conf  (配置文件路径)
│   ├── cgroup.yml                 (be单机多实例部署时cgroup配置项)
│   ├── hosts                      (ansiable主机列表)
│   ├── scale_be_vars.yml          
│   └── setup_vars.yml             (部署参数)
├── core  (playbook路径)
│   ├── scale_be_start.yml         (be批量启动playbook)
│   ├── scale_be.yml               (be部署playbook)
│   ├── scale_fe.yml               (fe部署playbook)
│   └── templates   (doris配置文件模板路径)
│       ├── be.conf.j2             (be配置文件模板)
│       ├── doris_be_supervisor_multi.ini.j2      (be_supervisor多实例配置文件模板)
│       ├── doris_be_supervisor_single.ini.j2     (be_supervisor单机部署配置文件模板)
│       ├── doris_fe_supervisor.ini.j2            (fe_supervisor配置文件模板)
│       └── fe.conf.j2              (fe配置文件模板)
└── pack             (Doris安装包及jdk安装包存放路径)
    ├── apache-doris-2.1.7-bin-x64-noavx2.tar.gz
    └── jdk-8u271-linux-x64.tar.gz

配置文件

hosts

ini 复制代码
[doris_be_scale]
10.2.2.242 ansible_port=36000
10.2.2.145 ansible_port=36000
10.2.2.252 ansible_port=36000
[doris_fe_scale]
10.2.2.245 ansible_port=36000

需要部署be的主机ip写到[doris_be_scale]下方

需要部署fe的主机ip写到[doris_be_scale]下方

ansible_port=36000是当目标主机ssh端口不是默认22时设置的,如果ssh端口为22,可以去掉该参数

setup_vars.yml

yaml 复制代码
---
################################  BE  ######################################
#be如果需要进行单机多实例部署,按照如下配置进行编写
# be_port_v:
#   - 9061
#   - 9062

# be端口设置
be_port_v:
  - 9060
  - 9061
webserver_port_v:
  - 8040
  - 8041
heartbeat_service_port_v:
  - 9050
  - 9051
brpc_port_v:
  - 8060
  - 8061
# doris_be存储目录
storage_path: 
  - /data/data1/doris
  - /data/data2/doris
# jdbc驱动包路径
jdbc_drivers_dir_v: /home/doris/apache-doris/jdbc_drivers
################################  FE  ######################################
#fe 配置
http_port_v: 8030
rpc_port_v: 9020
query_port_v: 9030
edit_log_port_v: 9010
meta_dir_v: /data/data/fe/fe_meta
LOG_DIR_v: /data/data/doris/log
lower_case_table_names_v: 0
#拓展fe节点是写master_ip:port
#例如fe_leader:10.2.2.245:9010
#如新部署,则为空
fe_leader:
##############################  公共配置  ####################################
# doris安装目录。
doris_be_home: 
  - /data/data1
  - /data/data2
doris_fe_home:
  - /data/data
#如果be需要单机多实例部署,如下
#doris_be_home:
#  - /data1
#  - /data2

#网络设置
priority_networks_v: 10.2.2.0/24
# jdk安装包路径
jdk_filepath: ../pack/jdk-8u271-linux-x64.tar.gz
# jdk安装目录
# 如果目标机器已经安装jdk,不需要重新安装,请将java_home填写成现有jdk安装路径
java_home: /usr/local/java/jdk1.8.0_271/
# doris安装包路径
doris_filepath: ../pack/apache-doris-2.1.7-bin-x64-noavx2.tar.gz

cgroup.yml

makefile 复制代码
#cgroup组
cgroup_group:
  - doris_be1
  - doris_be2
#cpu节点设置
cpus_set:
  - 0-1
  - 2-3
#内存节点设置
cpu_mems_set:
  - 0
  - 0
#最大内存限制
mem_limit:
  - 2G
  - 2G
#cgroup路径
cgroup_path : "/sys/fs/cgroup/"

根据实际情况填写,上述例子是单机2节点be安装。机器配置为4c4g

操作指引

  1. 根据需要填写hosts、setup_vars.yml、cgroup.yml

  2. 检查目标机器是否已经做过互信,ssh目标机器,如无需密码即为完成互信

  3. 将Doris安装包,jdk安装包(如果已经安装则不需要上传)上传至doris_ansible/pack目录。

  4. 执行ansiable-playbook

    1. 部署FE ansible-playbook -i doris_ansible/conf/hosts doris_ansible/core/scale_fe.yml
    2. 部署BE ansible-playbook -i doris_ansible/conf/hosts doris_ansible/core/scale_be.yml

FE扩容

markdown 复制代码
[root@localhost ~]# ansible-playbook -i doris_ansible/conf/hosts doris_ansible/core/scale_fe.yml 

PLAY [doris_fe_scale] *************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [10.2.2.245]

TASK [create group doris(创建用户组doris)] *********************************************************************************************************************************************
ok: [10.2.2.245]

TASK [create user doris(创建用户doris)] ***********************************************************************************************************************************************
ok: [10.2.2.245]

TASK [check java(检查java是否安装)] *****************************************************************************************************************************************************
ok: [10.2.2.245]

TASK [mkdir java home_path(创建java安装目录)] *******************************************************************************************************************************************
ok: [10.2.2.245]

TASK [install java(解压缩java安装包)] ***************************************************************************************************************************************************
skipping: [10.2.2.245]

TASK [mkdir fe home_path(创建fe安装目录)] ***********************************************************************************************************************************************
ok: [10.2.2.245] => (item=/data/data)

TASK [Check if fe binary exists in each installation directory(检查fe二进制文件是否存在)] ****************************************************************************************************
ok: [10.2.2.245] => (item=/data/data)

TASK [unarchive doris(解压BE安装包)] ***************************************************************************************************************************************************
skipping: [10.2.2.245] => (item={u'failed': False, u'stat': {u'charset': u'us-ascii', u'uid': 1001, u'exists': True, u'attr_flags': u'', u'woth': False, u'device_type': 0, u'mtime': 1730879331.0, u'block_size': 4096, u'inode': 403481468, u'isgid': False, u'size': 8117, u'executable': True, u'roth': True, u'isuid': False, u'readable': True, u'isreg': True, u'version': u'18446744073313675030', u'pw_name': u'doris', u'gid': 1001, u'ischr': False, u'wusr': True, u'writeable': True, u'isdir': False, u'blocks': 16, u'xoth': True, u'rusr': True, u'nlink': 1, u'issock': False, u'rgrp': True, u'gr_name': u'doris', u'path': u'/data/data/fe/bin/start_fe.sh', u'xusr': True, u'atime': 1733987588.5360384, u'mimetype': u'text/plain', u'ctime': 1733987159.17523, u'wgrp': False, u'checksum': u'6781c8fa6c827c181b8ae0b0deae01f01a0e3490', u'dev': 2064, u'isblk': False, u'isfifo': False, u'mode': u'0755', u'xgrp': True, u'islnk': False, u'attributes': []}, u'ansible_loop_var': u'item', u'item': u'/data/data', u'invocation': {u'module_args': {u'follow': False, u'get_checksum': True, u'path': u'/data/data/fe/bin/start_fe.sh', u'checksum_algorithm': u'sha1', u'get_md5': False, u'get_mime': True, u'get_attributes': True}}, u'changed': False}) 

TASK [mkdir fe storage(创建fe存储目录)] *************************************************************************************************************************************************
ok: [10.2.2.245] => (item=/data/data/fe/fe_meta)

TASK [create fe conf(创建fe配置文件)] ***************************************************************************************************************************************************
ok: [10.2.2.245]

TASK [change fe owner(更改fe目录属主)] **************************************************************************************************************************************************
ok: [10.2.2.245]

TASK [change fe owner(更改fe目录属主)] **************************************************************************************************************************************************
ok: [10.2.2.245]

TASK [Check if supervisor is installed(检查supervisor是否安装)] *************************************************************************************************************************
ok: [10.2.2.245]

TASK [Install epel-release(安装epel仓库)] *********************************************************************************************************************************************
ok: [10.2.2.245]

TASK [Install supervisor via yum if not present(安装supervisor)] ********************************************************************************************************************
ok: [10.2.2.245]

TASK [Create supervisor config for Doris FE(创建supervisor配置文件)] ********************************************************************************************************************
changed: [10.2.2.245]

TASK [start be] *******************************************************************************************************************************************************************
skipping: [10.2.2.245] => (item=/data/data) 

TASK [移除start_fe.sh中 '&'] *********************************************************************************************************************************************************
ok: [10.2.2.245]

TASK [修改supervisor.conf minfds 值为 1000000] ****************************************************************************************************************************************
changed: [10.2.2.245]

TASK [重启supervisord服务] ************************************************************************************************************************************************************
changed: [10.2.2.245]

TASK [Check if supervisor is running(检查supervisord是否启动)] **************************************************************************************************************************
ok: [10.2.2.245]

TASK [Reread and Update supervisor config(supervisor加载文件及更新)] *********************************************************************************************************************
changed: [10.2.2.245]

TASK [Stop Doris FE(停止doris_fe进程)] ************************************************************************************************************************************************
changed: [10.2.2.245]

TASK [Check if Doris BE is running(检查doris_fe进程是否启动)] *****************************************************************************************************************************
changed: [10.2.2.245]

TASK [Show result(输出doris_fe进程状态信息)] **********************************************************************************************************************************************
ok: [10.2.2.245] => {
    "msg": [
        "doris_fe                         STOPPED   Dec 13 11:27 AM"
    ]
}

PLAY RECAP ************************************************************************************************************************************************************************
10.2.2.245                 : ok=23   changed=6    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0   

BE扩容

python 复制代码
[root@localhost doris_ansible]# ansible-playbook -i conf/hosts core/scale_be.yml

PLAY [doris_be_scale] *************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************
fatal: [10.2.2.145]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 10.2.2.145 port 36000: No route to host", "unreachable": true}
ok: [10.2.2.242]
ok: [10.2.2.252]

TASK [create group doris(创建用户组doris)] *********************************************************************************************************************************************
ok: [10.2.2.252]
ok: [10.2.2.242]

TASK [create user doris(创建用户doris)] ***********************************************************************************************************************************************
ok: [10.2.2.242]
ok: [10.2.2.252]

TASK [check java(检查java是否安装)] *****************************************************************************************************************************************************
ok: [10.2.2.252]
ok: [10.2.2.242]

TASK [mkdir java home_path(创建java安装目录)] *******************************************************************************************************************************************
ok: [10.2.2.252]
ok: [10.2.2.242]

TASK [install java(解压缩java安装包)] ***************************************************************************************************************************************************
skipping: [10.2.2.242]
skipping: [10.2.2.252]

TASK [mkdir be home_path(创建be安装目录)] ***********************************************************************************************************************************************
ok: [10.2.2.242] => (item=/data/data1)
ok: [10.2.2.252] => (item=/data/data1)
ok: [10.2.2.242] => (item=/data/data2)
ok: [10.2.2.252] => (item=/data/data2)

TASK [Check if BE binary exists in each installation directory(检查be二进制文件是否存在)] ****************************************************************************************************
ok: [10.2.2.242] => (item=/data/data1)
ok: [10.2.2.252] => (item=/data/data1)
ok: [10.2.2.242] => (item=/data/data2)
ok: [10.2.2.252] => (item=/data/data2)

TASK [unarchive doris(解压BE安装包)] ***************************************************************************************************************************************************
skipping: [10.2.2.242] => (item={u'failed': False, u'stat': {u'charset': u'us-ascii', u'uid': 1001, u'exists': True, u'attr_flags': u'', u'woth': False, u'device_type': 0, u'mtime': 1730879332.0, u'block_size': 4096, u'inode': 134382560, u'isgid': False, u'size': 12018, u'executable': True, u'roth': True, u'isuid': False, u'readable': True, u'isreg': True, u'version': u'1492749182', u'pw_name': u'doris', u'gid': 1001, u'ischr': False, u'wusr': True, u'writeable': True, u'isdir': False, u'blocks': 24, u'xoth': True, u'rusr': True, u'nlink': 1, u'issock': False, u'rgrp': True, u'gr_name': u'doris', u'path': u'/data/data1/be/bin/start_be.sh', u'xusr': True, u'atime': 1734000561.657362, u'mimetype': u'text/plain', u'ctime': 1734000524.7656057, u'wgrp': False, u'checksum': u'87b8a550cc760b5dbbae9fcc961437db69005bd9', u'dev': 2064, u'isblk': False, u'isfifo': False, u'mode': u'0755', u'xgrp': True, u'islnk': False, u'attributes': []}, u'ansible_loop_var': u'item', u'item': u'/data/data1', u'invocation': {u'module_args': {u'follow': False, u'get_checksum': True, u'path': u'/data/data1/be/bin/start_be.sh', u'checksum_algorithm': u'sha1', u'get_md5': False, u'get_mime': True, u'get_attributes': True}}, u'changed': False}) 
skipping: [10.2.2.242] => (item={u'failed': False, u'stat': {u'charset': u'us-ascii', u'uid': 1001, u'exists': True, u'attr_flags': u'', u'woth': False, u'device_type': 0, u'mtime': 1730879332.0, u'block_size': 4096, u'inode': 134269890, u'isgid': False, u'size': 12018, u'executable': True, u'roth': True, u'isuid': False, u'readable': True, u'isreg': True, u'version': u'18446744072778930415', u'pw_name': u'doris', u'gid': 1001, u'ischr': False, u'wusr': True, u'writeable': True, u'isdir': False, u'blocks': 24, u'xoth': True, u'rusr': True, u'nlink': 1, u'issock': False, u'rgrp': True, u'gr_name': u'doris', u'path': u'/data/data2/be/bin/start_be.sh', u'xusr': True, u'atime': 1734000561.5733602, u'mimetype': u'text/plain', u'ctime': 1734000525.8206272, u'wgrp': False, u'checksum': u'87b8a550cc760b5dbbae9fcc961437db69005bd9', u'dev': 2064, u'isblk': False, u'isfifo': False, u'mode': u'0755', u'xgrp': True, u'islnk': False, u'attributes': []}, u'ansible_loop_var': u'item', u'item': u'/data/data2', u'invocation': {u'module_args': {u'follow': False, u'get_checksum': True, u'path': u'/data/data2/be/bin/start_be.sh', u'checksum_algorithm': u'sha1', u'get_md5': False, u'get_mime': True, u'get_attributes': True}}, u'changed': False}) 
skipping: [10.2.2.252] => (item={u'failed': False, u'stat': {u'charset': u'us-ascii', u'uid': 1001, u'exists': True, u'attr_flags': u'', u'woth': False, u'device_type': 0, u'mtime': 1730879332.0, u'block_size': 4096, u'inode': 402653314, u'isgid': False, u'size': 12018, u'executable': True, u'roth': True, u'isuid': False, u'readable': True, u'isreg': True, u'version': u'18446744072516289342', u'pw_name': u'doris', u'gid': 1001, u'ischr': False, u'wusr': True, u'writeable': True, u'isdir': False, u'blocks': 24, u'xoth': True, u'rusr': True, u'nlink': 1, u'issock': False, u'rgrp': True, u'gr_name': u'doris', u'path': u'/data/data1/be/bin/start_be.sh', u'xusr': True, u'atime': 1734054049.606421, u'mimetype': u'text/plain', u'ctime': 1734000524.4029808, u'wgrp': False, u'checksum': u'87b8a550cc760b5dbbae9fcc961437db69005bd9', u'dev': 2064, u'isblk': False, u'isfifo': False, u'mode': u'0755', u'xgrp': True, u'islnk': False, u'attributes': []}, u'ansible_loop_var': u'item', u'item': u'/data/data1', u'invocation': {u'module_args': {u'follow': False, u'get_checksum': True, u'path': u'/data/data1/be/bin/start_be.sh', u'checksum_algorithm': u'sha1', u'get_md5': False, u'get_mime': True, u'get_attributes': True}}, u'changed': False}) 
skipping: [10.2.2.252] => (item={u'failed': False, u'stat': {u'charset': u'us-ascii', u'uid': 1001, u'exists': True, u'attr_flags': u'', u'woth': False, u'device_type': 0, u'mtime': 1730879332.0, u'block_size': 4096, u'inode': 402784073, u'isgid': False, u'size': 12018, u'executable': True, u'roth': True, u'isuid': False, u'readable': True, u'isreg': True, u'version': u'18446744072650006313', u'pw_name': u'doris', u'gid': 1001, u'ischr': False, u'wusr': True, u'writeable': True, u'isdir': False, u'blocks': 24, u'xoth': True, u'rusr': True, u'nlink': 1, u'issock': False, u'rgrp': True, u'gr_name': u'doris', u'path': u'/data/data2/be/bin/start_be.sh', u'xusr': True, u'atime': 1734054049.4594178, u'mimetype': u'text/plain', u'ctime': 1734000525.3360002, u'wgrp': False, u'checksum': u'87b8a550cc760b5dbbae9fcc961437db69005bd9', u'dev': 2064, u'isblk': False, u'isfifo': False, u'mode': u'0755', u'xgrp': True, u'islnk': False, u'attributes': []}, u'ansible_loop_var': u'item', u'item': u'/data/data2', u'invocation': {u'module_args': {u'follow': False, u'get_checksum': True, u'path': u'/data/data2/be/bin/start_be.sh', u'checksum_algorithm': u'sha1', u'get_md5': False, u'get_mime': True, u'get_attributes': True}}, u'changed': False}) 

TASK [mkdir be storage(创建be存储目录)] *************************************************************************************************************************************************
ok: [10.2.2.242] => (item=/data/data1/doris)
ok: [10.2.2.252] => (item=/data/data1/doris)
ok: [10.2.2.242] => (item=/data/data2/doris)
ok: [10.2.2.252] => (item=/data/data2/doris)

TASK [create be conf(创建be配置文件)] ***************************************************************************************************************************************************
ok: [10.2.2.242] => (item=0)
ok: [10.2.2.252] => (item=0)
ok: [10.2.2.242] => (item=1)
ok: [10.2.2.252] => (item=1)

TASK [change be owner(更改be目录属主)] **************************************************************************************************************************************************
ok: [10.2.2.252] => (item=/data/data1)
ok: [10.2.2.242] => (item=/data/data1)
ok: [10.2.2.252] => (item=/data/data2)
ok: [10.2.2.242] => (item=/data/data2)

TASK [start be] *******************************************************************************************************************************************************************
skipping: [10.2.2.242] => (item=/data/data1) 
skipping: [10.2.2.242] => (item=/data/data2) 
skipping: [10.2.2.252] => (item=/data/data1) 
skipping: [10.2.2.252] => (item=/data/data2) 

TASK [install cgroup(安装libcgroup-tools)] ******************************************************************************************************************************************
ok: [10.2.2.252]
ok: [10.2.2.242]

TASK [create cgroup group(创建cgroup组)] *********************************************************************************************************************************************
changed: [10.2.2.252] => (item=doris_be1)
changed: [10.2.2.242] => (item=doris_be1)
changed: [10.2.2.242] => (item=doris_be2)
changed: [10.2.2.252] => (item=doris_be2)

TASK [modify cpuset.cpus(修改cpuset.cpus内容)] ****************************************************************************************************************************************
changed: [10.2.2.252] => (item=0)
changed: [10.2.2.242] => (item=0)
changed: [10.2.2.252] => (item=1)
changed: [10.2.2.242] => (item=1)

TASK [modify cpuset.mems(修改cpuset.mems内容)] ****************************************************************************************************************************************
changed: [10.2.2.242] => (item=0)
changed: [10.2.2.252] => (item=0)
changed: [10.2.2.252] => (item=1)
changed: [10.2.2.242] => (item=1)

TASK [modify memory.limit_in_bytes(修改memory.limit_in_bytes内容)] ********************************************************************************************************************
changed: [10.2.2.252] => (item=0)
changed: [10.2.2.242] => (item=0)
changed: [10.2.2.242] => (item=1)
changed: [10.2.2.252] => (item=1)

TASK [modify cpuset folder owner(修改cpuset文件夹属主)] **********************************************************************************************************************************
changed: [10.2.2.242] => (item=doris_be1)
changed: [10.2.2.252] => (item=doris_be1)
changed: [10.2.2.252] => (item=doris_be2)
changed: [10.2.2.242] => (item=doris_be2)

TASK [modify memory folder group(修改memory文件夹属主)] **********************************************************************************************************************************
changed: [10.2.2.242] => (item=doris_be1)
changed: [10.2.2.252] => (item=doris_be1)
changed: [10.2.2.242] => (item=doris_be2)
changed: [10.2.2.252] => (item=doris_be2)

TASK [Check if supervisor is installed(检查supervisor是否安装)] *************************************************************************************************************************
ok: [10.2.2.242]
ok: [10.2.2.252]

TASK [Install epel-release(安装epel仓库)] *********************************************************************************************************************************************
ok: [10.2.2.252]
ok: [10.2.2.242]

TASK [Install supervisor via yum if not present(安装supervisor)] ********************************************************************************************************************
ok: [10.2.2.242]
ok: [10.2.2.252]

TASK [Create supervisor config for Doris BE(创建supervisor配置文件)] ********************************************************************************************************************
ok: [10.2.2.242] => (item=0)
ok: [10.2.2.252] => (item=0)
ok: [10.2.2.242] => (item=1)
ok: [10.2.2.252] => (item=1)

TASK [Create supervisor config for Doris BE(创建supervisor配置文件)] ********************************************************************************************************************
skipping: [10.2.2.242]
skipping: [10.2.2.252]

TASK [设置 vm.max_map_count =2000000 ----/etc/sysctl.conf] **************************************************************************************************************************
ok: [10.2.2.252]
ok: [10.2.2.242]

TASK [生效内核配置] *********************************************************************************************************************************************************************
changed: [10.2.2.242]
changed: [10.2.2.252]

TASK [设置文件描述符 soft nofile limit] **************************************************************************************************************************************************
ok: [10.2.2.242]
ok: [10.2.2.252]

TASK [设置文件描述符 hard nofile limit] **************************************************************************************************************************************************
ok: [10.2.2.242]
ok: [10.2.2.252]

TASK [修改supervisor.conf minfds 值为 1000000] ****************************************************************************************************************************************
ok: [10.2.2.242]
ok: [10.2.2.252]

TASK [重启supervisord服务] ************************************************************************************************************************************************************
changed: [10.2.2.252]
changed: [10.2.2.242]

TASK [Check if supervisor is running(检查supervisord是否启动)] **************************************************************************************************************************
ok: [10.2.2.252]
ok: [10.2.2.242]

TASK [Start supervisor if not running(启动supervisor)] ******************************************************************************************************************************
skipping: [10.2.2.242]
skipping: [10.2.2.252]

TASK [Reread and Update supervisor config(supervisor加载文件及更新)] *********************************************************************************************************************
changed: [10.2.2.242]
changed: [10.2.2.252]

TASK [Check if Doris BE is running(检查doris_be进程是否启动)] *****************************************************************************************************************************
changed: [10.2.2.252]
changed: [10.2.2.242]

TASK [Show result(输出doris_be进程状态信息)] **********************************************************************************************************************************************
ok: [10.2.2.242] => {
    "msg": [
        "doris_be1                        STARTING  ", 
        "doris_be2                        STARTING  "
    ]
}
ok: [10.2.2.252] => {
    "msg": [
        "doris_be1                        RUNNING   pid 32153, uptime 0:00:42", 
        "doris_be2                        RUNNING   pid 32152, uptime 0:00:42"
    ]
}

PLAY RECAP ************************************************************************************************************************************************************************
10.2.2.145                 : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
10.2.2.242                 : ok=31   changed=10   unreachable=0    failed=0    skipped=5    rescued=0    ignored=0   
10.2.2.252                 : ok=31   changed=10   unreachable=0    failed=0    skipped=5    rescued=0    ignored=0   
相关推荐
袁煦丞33 分钟前
Photopea云端修图不求人!cpolar内网穿透实验室第641个成功挑战
前端·程序员·远程工作
yk-ddm39 分钟前
JavaScript实现文件下载完整方案
前端·javascript·html
万少1 小时前
04-自然壁纸实战教程-搭建基本工程
前端·harmonyos·客户端
karl_hg1 小时前
Element Plus 自定义(动态)表单组件
前端·vue.js·element
南岸月明1 小时前
从焦虑到专注:副业半年后我才明白的3件事
前端
晓13131 小时前
JavaScript加强篇——第八章 高效渲染与正则表达式
开发语言·前端·javascript
南囝coding2 小时前
做付费社群,强烈建议大家做这件事!
前端·后端
我是若尘2 小时前
Axios 如何跨域携带 Cookie?
前端
子林super2 小时前
主从数据全量迁移到分片集群测试
前端
Spider_Man2 小时前
🚀 TypeScript从入门到React实战:前端工程师的类型安全之旅
前端·typescript