2026年3月

图片

文末有源码下载链接

    在现代云原生架构中,容器化已经成为应用部署的标准方式。Docker通过“镜像+容器”的机制,让任何人可以轻松地:

  •     打包应用及其所有依赖
  •     所有环境保持一致:你的电脑能跑,服务器也能跑
  •     启动快、占用少、易扩展
  •     配合K8s实现自动扩容、滚动更新

1、为什么微服务都在用Docker?

    Docker出现之前地痛点:

  • Go代码在本机运行正常,部署到服务器后各种依赖缺失
  • 配置环境、装依赖、升级版本非常麻烦
  • 多服务部署搞得像“盘丝洞”,环境乱成一锅粥
  • 回滚、扩容、迁移都很困难

    Docker出现后解决了什么?

  • 将应用、依赖、运行环境一起封装成镜像
  • 镜像是不可变的,哪里都能跑
  • 启动容器只需要几百毫秒
  • 天然适配K8s、CI/CD

    一句话:用Docker = 构建“可复制、可迁移、有保障”地部署流程

2、准备一套完整的web服务

package server
func StartHTTPServer(host string, port int) error {
    zap.L().Info("正在初始化服务器...")
    mode := viper.GetString("server.mode")
    switch mode {
    case "dev":
        gin.SetMode(gin.DebugMode)
    case "prod":
        gin.SetMode(gin.ReleaseMode)
    case "test":
        gin.SetMode(gin.TestMode)
    default:
        gin.SetMode(gin.DebugMode)
    }
    components.Init()         // 初始化各个组件
    migrates.DoMigrate()      // 数据库迁移
    services.InitServices()   // 初始化服务层
    r := routers.InitRouter() // 初始化路由
    s := &http.Server{
        Addr:           fmt.Sprintf(`%s:%d`, host, port),
        Handler:        r,
        ReadTimeout:    time.Duration(viper.GetInt("server.readtimeout")) * time.Second,
        WriteTimeout:   time.Duration(viper.GetInt("server.writertimeout")) * time.Second,
        MaxHeaderBytes: 1 << 20,
    }
    // 启动HTTP服务
    go func() {
        zap.L().Info("HTTP服务器启动了", zap.String("addr", s.Addr))
        if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            zap.L().Fatal("HTTP服务器启动失败", zap.Error(err))
        }
    }()
    //告诉k8s或者docker我准备好了
    services.SetReady()
    // 捕获系统信号
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)
    <-quit
    zap.L().Warn("收到关闭信号,正在优雅退出...")
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    s.SetKeepAlivesEnabled(false) // 避免新的连接进来
    if err := s.Shutdown(ctx); err != nil {
        fmt.Println("服务器被强制关闭了:", err)
    }
    zap.L().Info("服务器优雅退出了")
    return nil
}

3、编写Dockerfile(敲黑板)

Go容器镜像最佳实践---多阶段构建(multi-stage build)

# 第一阶段:构建阶段
FROM golang:1.23-alpine AS builder
#LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式
LABEL maintainer="Codee君"
#设置容器Go语言环境变量
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct
#为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录
WORKDIR /go/release
#COPY 拷贝文件或目录到容器中,跟ADD类似,但不具备自动下载或解压的功能
COPY . .
#RUN 构建镜像时运行的指令
#sed 命令用于文本处理,这里是用来替换 Alpine Linux 的软件源镜像为中科大的镜像
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk update && apk add tzdata
#安装swago,并自动生成API文档
RUN go install github.com/swaggo/swag/cmd/swag@v1.8.10 
RUN swag init  --parseDependency=true
#go build 编译程序
RUN CGO_ENABLED=0 GOOS=linux go build -p 1 -ldflags="-w -s" -a -installsuffix cgo -o golang_per_day .
# 第二阶段:运行阶段
FROM alpine:latest
# 把第一阶段构建的二进制文件和依赖拷贝到新的镜像中
COPY --from=builder /go/release/golang_per_day /
COPY --from=builder /go/release/configs /configs
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#EXPOSE 声明容器的服务端口(仅仅是声明)
EXPOSE 8080
#CMD 运行容器时执行的shell命令
CMD ["/golang_per_day_30","server","-c", "/configs/config.yaml"]

为什么要多阶段构建?

  • 避免把整个Go编译环境打进最终的镜像
  • builder阶段 > 1GB
  • alpine阶段 < 100MB
  • 最终镜像只有几十MB,非常适合云原生

4、构建Docker镜像

在项目根目录执行:

$ docker build --no-cache -t imoowi/golang_per_day_30 .

图片

5、把镜像push到仓库,这里用的docker的公共仓库,如果你需要私有仓库,请去其他云厂商购买或者自己搭建。

$ docker login -u 你的用户名

i Info → A Personal Access Token (PAT) can be used instead.
          To create a PAT, visit https://app.docker.com/settings
Password: 输入密码
Login Succeeded
$ docker push imoowi/golang_per_day_30
Using default tag: latest
The push refers to repository [docker.io/imoowi/golang_per_day_30]
68578effd277: Pushed
94ffa90d46ab: Pushed
b7012b08af98: Pushed
0f4970872d39: Pushed
418dccb7d85a: Mounted from library/alpine
latest: digest: sha256:bad95cb900e0758a4cfeb7d8e3fe284911b1d60bd5fd19ab19b69dd2044b5ecb size: 1364

6、运行容器

docker
8080
8080

图片

浏览器访问http://localhost:8080/swagger/index.html

图片

7、用Docker Compose管理多个服务(Go+MySQL+Redis)

7.1 配置docker-compose.yml文件

version: "3"
networks:
    #定义一个名为codee_jun的网络
    codee_jun:
      driver: bridge
services:
  mysql:
    container_name: mysql
    image: mysql:5.7
    ports:
        - 3306:3306
    environment:
        MYSQL_ROOT_PASSWORD: "123456"
    volumes:
        # 数据库挂载目录
        - ./docker-data/mysql/data:/var/lib/mysql
        # 数据库初始化脚本挂载目录
        - ./configs/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    command: [
        '--character-set-server=utf8mb4',
        '--collation-server=utf8mb4_unicode_ci',
        '--max_connections=3000'
    ]
    restart: always
    networks:
        - codee_jun
  redis:
    container_name: redis
    image: redis:latest
    command: redis-server --requirepass 123456
    ports: 
        - 6379:6379
    volumes:
        - ./docker-data/redis/db:/data
    restart: always
    networks:
        - codee_jun
  golang_per_day_30:
    container_name: golang_per_day_30
    build: .
    ports:
      - 8080:8080
    # 依赖的服务,必须先启动依赖的服务,才能启动当前服务
    depends_on:
        - mysql
        - redis
    volumes:
      - ./configs:/configs
    restart: always
    networks:
        - codee_jun

7.2 添加初始化sql

---configs/init.sql
CREATE DATABASE IF NOT EXISTS `golang_per_day` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `golang_per_day`;

7.2 启动服务

$ docker-compose up -d 
[+] Running 4/4
 ✔ Network golang_per_day_30_codee_jun  Created                                                                                                                                   0.1s 
 ✔ Container redis                      Started                                                                                                                                   0.6s 
 ✔ Container mysql                      Started                                                                                                                                   0.6s 
 ✔ Container golang_per_day_30          Started  

7.3 关闭服务

$ docker-compose down
 ✔ Container golang_per_day_30          Removed                                                                                                                                   0.4s 
 ✔ Container mysql                      Removed                                                                                                                                   2.1s 
 ✔ Container redis                      Removed                                                                                                                                   0.5s 
 ✔ Network golang_per_day_30_codee_jun  Removed 

7.4 注意 文件configs/config.docker.yaml 里,mysql和redis的主机地址,现在分别写的是同网络下的服务的名字,而不再是localhost,一定要注意。

#configs/config.docker.yaml
mysql:
  dsn: root:123456@tcp(mysql:3306)/golang_per_day?charset=utf8&parseTime=True&loc=Local&timeout=1000ms
redis:
  addr: "redis:6379"
  password: "123456"
  db: 0
#docker-compose.yml
version: "3"
networks:
    #定义一个名为codee_jun的网络
    codee_jun:
      driver: bridge
services:
  mysql: 这个名字就是配置文件里对应的服务名
  redis:

8、部署到K8S

8.1 Deployment(核心,部署Go服务),文件k8s/deployment.yaml

#k8s/deployment.yaml
apiVersion: apps/v1 #定义应用部署的API版本
kind: Deployment #定义部署应用
metadata: #元数据部分
  name: golang-per-day-30 #这里填写部署名称
  namespace: codee_jun #这里填写命名空间
spec:
  #replicas表示期望运行的Pod副本数量
  replicas: 1 #这里填写副本数量
  #选择器,定义如何选择Pod
  selector:
    matchLabels: #选择标签,匹配具有特定标签的Pod
      app: golang-per-day-30 #这里填写标签名称
  #模板,定义Pod的规格
  template:
    metadata: #Pod的元数据
      labels: #标签部分
        app: golang-per-day-30 #这里填写标签名称
    spec: #Pod的规格部分
      containers: #定义容器
        - name: golang-per-day-30 #这里填写容器名称
          image: golang_per_day_30:latest #这里填写镜像名称
          ports: #定义容器端口
            - containerPort: 8080 #容器内部端口
          volumeMounts: #定义卷挂载
            - name: golang_per_day_30-configmap
              mountPath: /configs/config.docker.yaml #容器内挂载路径
              subPath: config.yaml #子路径
          resources: #定义资源请求和限制
            requests: #资源请求
              cpu: 1000m #请求的CPU资源
              memory: 2Gi #请求的内存资源
            limits: #资源限制
              cpu: 2000m #限制的CPU资源
              memory: 4Gi #限制的内存资源
      volumes:
        - name: golang_per_day_30-configmap #卷名称
          configMap: 
            name: golang-per-day-30-configmap #引用的configmap名称

8.2 服务(Service) (给Pod提供稳定访问),文件k8s/service.yaml

#k8s/service.yaml
apiVersion: v1
kind: Service #定义服务
metadata:
  name: golang-per-day-30 #这里填写服务名称
  namespace: codee_jun #这里填写命名空间
spec: #服务规格
  # externalIPs:
  #   - 123.59.187.137
  ports:
    - protocol: TCP 
      port: 80 #服务端口
      targetPort: 80 #目标端口(容器端口)
  sessionAffinity: ClientIP #会话亲和性设置为ClientIP
  selector: 
    app: golang-per-day-30  #选择标签,匹配具有特定标签的Pod

8.3 ConfigMap(配置文件),文件k8s/configmap.yaml

apiVersion: v1 #定义API版本
kind: ConfigMap #定义资源类型
metadata:
  name: golang-per-day-30-configmap #这里填写ConfigMap名称
  namespace: codee_jun #这里填写命名空间
data:
  config.yaml: |
    server:
      mode: "prod"
      port: 8080
      host: 0.0.0.0
      readtimeout: 60
      writetimeout: 60
    log:
      level: "info"
    mysql:
      dsn: root:123456@tcp(mysql.codee_jun.svc.cluster.local:3306)/golang_per_day?charset=utf8&parseTime=True&loc=Local&timeout=1000ms
    redis:
      addr: "redis.codee_jun.svc.cluster.local:6379"
      password: "123456"
      db: 0
    jwt:
      secret: "golang_per_day_secret_key"
      # 24h表示24小时
      expire: 24h
    ratelimit:
      # 每秒放多少个令牌
      cap: 1000
      # 每秒取多少个令牌
      quantum: 1000

注意:mysql地址变成了mysql.codee\_jun.svc.cluster.local,redis的地址变成了redis.codee\_jun.svc.cluster.local,这是k8s集群内部服务的访问格式,你也可以用云数据库,在这里直接替换即可。

8.4 自动扩容HPA(水平自动扩容),文件k8s/hpa.yaml

apiVersion: autoscaling/v2 #定义API版本
kind: HorizontalPodAutoscaler #定义水平Pod自动扩缩容器
metadata: #元数据
  name: golang-per-day-30-hpa #这里填写HPA名称
  namespace: codee_jun #这里填写命名空间
spec: #HPA规格
  scaleTargetRef:
    apiVersion: apps/v1 #定义API版本
    kind: Deployment #定义资源类型
    name: golang-per-day-30 #这里填写Deployment名称
  minReplicas: 1 #最小副本数
  maxReplicas: 10 #最大副本数
  metrics:  #指标集合
    - type: Resource #资源指标类型
      resource: #资源指标
        name: cpu #资源名称
        target:  #资源目标值
          type: Utilization #CPU利用率目标
          averageUtilization: 80 #CPU利用率目标值
    - type: Resource
      resource:
        name: memory #内存资源名称
        target:
          type: Utilization #内存利用率目标
          averageUtilization: 80 #内存利用率目标值

8.5 Ingress (域名访问), k8s/ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: golang_per_day_30-ingress
  namespace: codee_jun
  annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://golang_per_day_30.com"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true" # 如果需要凭证
    nginx.ingress.kubernetes.io/proxy-body-size: "1024m"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "golang_per_day_30-session"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
spec:
  rules:
    - host: golang_per_day_30.com # 域名
      http: # 协议
        paths: # 路径
          - path: / # 路径
            pathType: Prefix   # 路径类型
            backend: # 后端
              service: # 服务
                name: golang-per-day-30 # 服务名称
                port: # 服务端口
                  number: 8080 # 服务端口号

8.6 部署一条龙

进入k8s目录

kubectl apply -f .

查看部署情况

$ kubectl get pods -n orth -o wide | grep golang_per_day_30
golang_per_day_30-56c4c7f685-2tm7g                    1/1     Running     0          1m10s    172.16.10.47    cn-beijing.10.16.233.81    <none>           <none>
golang_per_day_30-56c4c7f685-8q9zn                    1/1     Running     0          1m10s    172.16.10.91    cn-beijing.10.12.229.121   <none>           <none>
golang_per_day_30-56c4c7f685-mbrnv                    1/1     Running     0          1m10s    172.16.10.16    cn-beijing.10.16.233.81    <none>           <none>  
golang_per_day_30-56c4c7f685-vf8t6                    1/1     Running     0          1m10s    172.16.10.99    cn-beijing.10.12.229.121   <none>           <none>    

查看服务

$ kubectl get svc -n codee_jun | grep golang_per_day_30
golang_per_day_30                       ClusterIP   192.168.1.109    <none>        80/TCP      5m

查看ingress地址

$ kubectl get ingress -n codee_jun | grep golang_per_day_30
golang_per_day_30-ingress   nginx   golang_per_day_30.com   a.b.c.d    8080   10m

测试访问浏览器访问地址http://golang\_per\_day\_30.com,如果域名解析成功,即可访问服务

8.7 滚动更新,Deployment默认就是滚动更新,如何触发滚动更新呢?

    8.7.1 更新镜像

kubectl set image deployment/golang_per_day_30 golang_per_day_30=imoowi/golang_per_day_30:v2

    8.7.2 修改Deployment配置

kubectl apply -f deployment.yaml

    8.7.3 手动重启(强制滚动)

kubectl rollout restart deployment golang_per_day_30

*源码地址*

1、公众号“Codee君”回复“每日一Go”获取源码

2、https://pan.baidu.com/s/1B6pgLWfSgMngVeFfSTcPdg?pwd=jc1s 

人生的成长,也像 K8s 滚动更新:

不是推倒重来,而是在保持生活继续的同时,

慢慢替换掉旧的自己,让更好的版本上线。


如果您喜欢这篇文章,请点赞、推荐+分享给更多朋友,万分感谢!

pro plan 看了好几遍显示 3 月 3 日到期,没有具体时间点。
一个月重置的 usage 真的难用,高级模型扣扣索索的用随便几次用到 80%不敢再用了,想留着最后解决关键问题。
差不多最后一个星期,不知道更改计费了还是提高配额了,usage 从 80%跳到 40%了。大喜
最后两天搞个项目,想着 spec-driven ,最后来用自选模型一把生成。
结果干到 3.3 早上十点,直接显示已过期为 free plan 了。
月重置 usage 的计费方式,真的是用也不是,怕后面难题没得用;不用也不是,憋了半个月不舍得用,最后直接给烂锅里了。感觉如果只开 cursor 一家没有备用的用户,这种设计真的是为难人,最后逼人加钱。
auto 太不稳定了,有时候很强,有时候给你来泡大的。
cursor + 高级模型是真的好用,但也是真的难用~

创始人们!为了更深入与国内的创始人建立更密切的联系,Antler将在北京举办一天的线下活动。主题为 “Disrupt beyond borders”

活动分为两个环节:

1.预热环节: 我们将选出 12 位创始人,获得与 Antler 合伙人面对面,1-1,30 分钟 office hour 的机会,获取对项目的反馈,并有机会被快速推荐获得 Disrupt 的邀请。

2.主题论坛: 围绕“从中国打造全球化产品”展开两场小组讨论,嘉宾包括在该议题上有丰富经验的创始人、运营者和风投人士。

这不是另外一场只有夸夸其谈、商业互吹的「大会」,而是脚踏实地、展望全球的「实战场」,专为那些希望直接对话已功成身退的创始人与实战运营者、获取针对自身创业公司的真实反馈、以及汲取已踏入全球市场的团队毫无保留经验之谈的创始人而设。

你可以期待:

  • 实诚的创业故事
  • 战术级的操作建议
  • 立刻能用的实用框架
  • 来验证你的想法、挑战你的判断、认识那些从 Day 1 就瞄准国际市场的人

🗓日期:3月5日

📍地点:北京 (活动详细地址仅报名后可见)

🖐🏻报名:扫码或到 https\://hdxu.cn/1EPlA

⚡️福利:作为本次活动的合作伙伴,亚马逊云科技将为参加活动的符合条件*的创始人提供最高价值10万美元的免费云资源。

如果感兴趣,请到账号,通过置顶帖完成报名!

✦₊ 关于Antler

自创立之初,Antler (https\://www.antler.co/) 便始终致力于支持全球最具远见的创业者,并深信创新是引领世界迈向更美好未来的核心驱动力。秉承这一信念,Antler 已在全球超过30个城市设立分支机构,并在多个行业及前沿科技领域成功孵化和投资超过 1,600 家初创企业。我们专注于发掘并赋能具有高成长潜力的创新项目,以应对真实且重大的商业机遇与社会挑战。

Disrupt (https\://content.antler.co/zh-cn/disrupt) 是由 Antler 于2024年专为AI创业公司打造的4周加速计划,旨在为中国创业者提供通往国际舞台的桥梁,助力创始人实现更快、更远的发展。下一期 Disrupt 计划将于3月30日至4月24日在越南胡志明市举行。入选团队无需支付任何额外项目费用。若项目在第四周评审会上通过投资委员会审核,即可获得40万美元的投资支持,全程参与均免费。

阅读更多 Voice Agent 学习笔记:了解最懂 AI 语音的头脑都在思考什么

20 元套餐用户,主要是用于文字处理、百科问答、闲聊一类的用途,只用 pro(3.1 preview )模式,最近感觉回答质量有所降低,不知道是我个人感觉还是大家都有感觉?

为什么同一套网页代码,在你电脑的 Chrome 上显示完美,发给客户用苹果 Safari 打开,排版就全盘错位?

这并非你写错了代码,而是遇到了前端最底层的现实环境:各大浏览器厂商底层引擎存在差异

Chrome、Safari、Firefox 由不同公司开发,拥有各自的渲染引擎。如果不加限制,同一份代码在不同浏览器里必然会渲染出不同的表现。为了不让开发者被迫写多套代码去兼容不同设备,前端界制定了一套强制性的解析规范,也就是 Web 标准

1. Web 标准到底是什么?

💡 核心定律:标准是给浏览器定的底层规矩,不是面向开发者的编程教程。

很多新手误以为 Web 标准是教人如何写代码的书。其实完全相反,它是用来约束各大浏览器厂商的技术规范。

规范文档里写得极其明确:比如遇到 <button> 标签,浏览器必须默认渲染出一致的预设边距,遇到鼠标悬浮时必须具备固定的交互状态。正因为所有浏览器都必须遵守这套底线规矩,你写下的同一行代码,才能在全世界各种设备上显示一致。

2. 核心三巨头:各自的职责边界

在之前讲解的网页渲染流程中,我们提到浏览器如何解析代码。那么支撑其运转的三大核心技术(HTML、CSS、JS)究竟是如何分工的?

技术名词核心职责底层逻辑
HTML定义内容结构页面的骨架。仅用标签明确告诉浏览器“这是一个标题”或“这是一个按钮”,绝对不在这里处理排版和颜色。
CSS控制视觉样式页面的外观。通过选择器精准找到 HTML 元素,专门负责下达颜色、排版、尺寸等视觉渲染指令。
JavaScript处理动态交互页面的逻辑中枢。监听用户的操作(如点击),或向服务器拉取数据,然后动态修改当前的 HTML 结构或 CSS 样式。

3. 野生代码 vs 工业级写法(3 条实战铁律)

理解了浏览器的解析标准后,写代码就不能全凭直觉。业界总结出来的“最佳实践”,本质都是为了让代码结构更清晰、更利于机器解析和后期维护。

铁律一:HTML 语义化(让机器理清重点)

很多人图省事,所有排版全用 <div> 把文本框起来。在外行人看来,只要加了 CSS,这页面长得都一样。但在搜索引擎(如百度)和盲人辅助阅读设备眼里,这就是一堆毫无主次、杂乱无章的纯文本。

⚠️ 常见错误:全篇 div

<!-- 机器完全不知道这两行字的层级关系和具体功能 -->
<div class="large-text">我的博客</div>
<div class="link-btn">进入主页</div>

🛠️ 正确做法:语义化标签

<!-- 机器一秒读懂:h1 是页面唯一核心主题,nav 代表导航区域 -->
<h1>我的博客</h1>
<nav>进入主页</nav>

结论:用正确的标签做正确的事。大标题只用 h1~h6,要点击的交互入口只用 button 或是 <a> 链接。

铁律二:结构、样式、行为三层物理隔离

如果把样式和脚本强行写进 HTML 标签的属性里,叫做“内联写法”。这就相当于把静态结构、视觉表现和业务逻辑死死绑在一起。未来只要业务变大,你想全站统一修改某种按钮的交互或颜色时,只能逐个文件、逐行代码去人工修改,维护成本极高。

⚠️ 常见错误:高重度耦合

<!-- 极其臃肿,且无法被其他页面复用 -->
<button style="color: red;" onclick="alert('购买成功')">购买</button>

🛠️ 正确做法:三层严格分离

<!-- HTML(只管骨架:定义有什么元素) -->
<button id="buy-btn" class="btn-danger">购买</button>

<!-- CSS(只管外观:放在独立的 .css 文件中) -->
.btn-danger { color: red; }

<!-- JS(只管行为:放在独立的 .js 文件中) -->
document.getElementById('buy-btn').addEventListener('click', function() {
  alert('购买成功');
});

铁律三:响应式设计(消灭写死尺寸的恶习)

如今的设备屏幕有几十种物理分辨率。如果在 CSS 里将某个外部容器死死定为 width: 1200px,一旦用户在地铁上用手机打开,页面就会被生硬截断,出现极其难用的底部横向滚动条。

💡 核心定律:用相对单位替换绝对像素。
必须全面转向自适应的相对布局,优先使用百分比(%),配合媒体查询@media),让样式遇到不同设备宽度时能自动适配调整。

🛠️ 正确做法:用媒体查询判断设备宽度

/* 默认手机端小屏幕排版:内容上下堆叠排列 */
.container { 
  display: flex; 
  flex-direction: column; 
}

/* 只要屏幕宽度大于 768px(来到平板或电脑端屏幕),立刻改用横向并排 */
@media (min-width: 768px) {
  .container { flex-direction: row; }
}

📝 总结

无论你用什么框架开发,最终都要回归这 3 条底线规范:

  1. 语义化:用对标签,让机器能读懂层级。
  2. 代码分层:把 HTML、CSS、JS 物理拆分,方便后期维护。
  3. 响应式:放弃写死固定尺寸,用百分比和媒体查询适配所有屏幕。

坚守这三条底线,你的代码在任何浏览器下都能正常显示。


下一章预告:
上述所有的规范和代码拆分,处理的都是页面上能被用户直接看到的区域(即 <body> 里的内容)。
但在实际开发中,很多引发致命报错的问题(比如跨设备乱码、分享到微信时不显示图标、甚至首屏莫名其妙白屏报错)往往不是正文写错了,而是网页的配置出了问题。
下一章请看:【大白话前端 04】HTML 头部的底层逻辑:决定网页解析与检索的隐形配置单,我们将拆解 <head> 这个极易被新手忽略的网页元数据配置区。

开发者朋友们大家好:

这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 技术 」、「有亮点的 产品 」、「有思考的 文章 」、「有态度的 观点 」、「有看点的 活动 」,但内容仅代表编辑的个人观点,欢迎大家留言、跟帖、讨论。

本期编辑:@瓒an、@鲍勃

01 有话题的技术

1、通义实验室上线语音双模型:支持自然语言指令,自由控制音色与听觉场景

针对生僻字、复杂语句等容易读错的场景专项优化,生僻字读错率从 15.2% 降至 5.3%,复杂文本表现更加稳定,长文本朗读也更稳定流畅。

Fun-AudioGen-VD: 整体表现稳定,Avg-APS 达到 89.25,是该组测试中语音质量最高的模型之一。

3 月 2 日消息,通义实验室正式发布两款支持 FreeStyle 指令生成的语音双模型:Fun-CosyVoice3.5 与 Fun-AudioGen-VD。传统语音生成通常依赖固定的情绪选项或风格模板,而此次技术更新的核心突破在于摆脱预设标签,允许用户通过自然语言指令直接描述并控制声音表达、音色与场景

这两款模型均支持自然语言指令,但在具体应用方向上各有侧重:

  • Fun-CosyVoice3.5:侧重于多语种复刻与精细化表达控制。该模型新增了泰语、印尼语、葡萄牙语和越南语四种小语种。在准确性与性能方面,其生僻字读错率从 15.2% 降至 5.3%;通过强化学习技术调优,提升了韵律表现与复刻音质;同时将首包延迟降低了 35%,优化了实时交互的流畅度。
  • Fun-AudioGen-VD:聚焦于声音设计与场景化音频生成,支持「人物+场景」的一体化塑造。该模型不仅能通过指令精细控制性别、年龄、情绪甚至复杂心理等角色音色特征,还能模拟城市喧嚣、空间回声及老式广播等设备滤镜,打造带有动态互动的沉浸式听觉环境。

指令: 场景是在一家热闹的咖啡馆里。背景能听到磨豆机的嗡嗡声、瓷杯碰撞的清脆声,还有远处模糊的人声。说话人语气很松弛,就像是坐在对面跟你喝下午茶。

合成文本: 哎,你尝尝他家这个新品,味道挺特别的。我刚才还想呢,咱下周要不把老李也约出来?咱三个好久没凑一块儿坐坐了。

这两款模型的上线,使语音生成从基础的功能工具升级为可编排的创作工具。在影视动画、游戏及有声书等实际场景中,创作者能够通过自然语言快速定义目标声音,从而降低录制与调试成本。

相关文档:

https\://help.aliyun.com/zh/model-studio/cosyvoice-clone-api

(@通义实验室)

2、Core AI 框架取代 Core ML?曝苹果 WWDC 26 开发者大会将公布多项 AI 功能

3 月 1 日,彭博社记者马克·古尔曼在最新一期《Power On》通讯中表示,苹果计划在 WWDC 26 开发者大会上发布全新 Core AI 框架,取代现有的 Core ML

古尔曼表示,苹果不太可能一下子就让 Core AI 完全取代 Core ML,而且 6 月的发布会可能只是一次简单的更名,让该框架更加贴近当前的实际用途,毕竟苹果已经为 Core ML 提供大语言模型、扩散模型等集成。

并且,Core AI 框架还将帮助开发者在应用中集成第三方 AI 模型。不过目前我们并不清楚其具体实现方式,理论上来讲 MCP(模型上下文协议)是一种可行方案。

虽然此前曾有传闻称苹果 iOS 27 将类似 Mac OS X Snow Leopard 那样主打「零新功能」,以修复、提升稳定性为主。但苹果仍有可能会在 WWDC 26 上放出基于谷歌 Gemini 训练的 Apple 智能。

(@极客公园)

02 有亮点的产品

1、联想携两款桌面 AI 硬件亮相 MWC 2026:概念机器人与智能时钟重塑办公体验

3 月 2 日,2026 年世界移动通信大会(MWC)在巴塞罗那开幕。联想在现场展出了折叠游戏本、模块化笔记本等多款概念新品,并带来两款面向办公场景的 AI 硬件:桌面 AI 机器人 AI Workmate 与智能桌面时钟 AI Work Companion

这两款概念设备在形态与功能上各有侧重:

  • AI Workmate 桌面机器人:搭载英特尔酷睿 Ultra 处理器与 64GB 内存,正面配有 3.4 英寸 LCD 屏幕以显示表情。它支持语音、手势与本地 AI 处理,能扫描文档生成摘要并辅助制作 PPT。设备头部内置摄像头与微型投影模块,现场演示了投影图片、扫描纸质签名并直接发送打印的办公流程。该原型机主要探索空间与实体 AI 的应用,针对频繁语音交互可能产生的噪音问题,现场有反馈期望未来增加文字交互方式。
  • AI Work Companion 智能时钟:整体造型简约,顶部设有旋钮与自定义按键,正面屏幕主要显示日历与任务清单。它通过 USB-C 供电并可作为拓展坞为其他设备充电。其内置的 AI 「思维气泡」模式支持跨设备同步日程并自动生成每日计划,同时会监测屏幕使用时间、提醒定时休息,并在周末生成任务完成报告。

联想方面表示,这两款概念产品意在展示人工智能如何自然融入日常办公环境,在提升工作效率的同时兼顾健康的办公节奏。

(@AI 星球视界)

2、Timekettle 发布 W4 AI 翻译耳机,以骨传导与智能引擎攻克复杂环境拾音难题

3 月 1 日消息,人工智能翻译技术企业 Timekettle 宣布将首次亮相于 3 月 2 日至 5 日在巴塞罗那举行的 2026 年世界移动通信大会(MWC 2026)。继此前在 CES 和 IFA 等展会上展示创新成果后,Timekettle 此次重点展出了其高响应速度的 W4 AI 翻译耳机。

W4 翻译耳机搭载了全新的 Babel OS 2.0 系统,通过软硬件融合,主要解决跨语言交流中「语音拾取不清晰」和「翻译不准确」两大核心难题。 其系统集成了两项关键技术:

  • AI 骨传导拾音技术(AI Bone-Conduction Pickup):传统翻译耳机依赖空气传导麦克风,在嘈杂环境中容易受干扰。W4 改为直接从用户声带捕捉振动,将语音与环境噪音隔离,确保在机场、展会或繁华街道等复杂场景下依然能精准锁定用户声音。
  • 智能 SOTA 引擎选择器(SOTA Engine Selector):该功能可实时识别语言组合,并自动分配最适合该语种的翻译引擎。每个引擎均针对特定语法结构、表达模式及语境进行过优化,使商务谈判、技术讨论或日常对话的翻译效果更贴近母语使用者的自然表达。

通过构建纯净输入、智能引擎选择与精准输出的闭环系统,W4 提升了在复杂环境下的翻译稳定性。Timekettle 此次在 MWC 2026 的展出,体现了其将前沿技术与实际场景驱动设计相结合的产品思路,进一步推动了跨语言互动的自然性与准确性。

( @PR Newswire)

3、科大讯飞推出 AI 学习机 T90 Pro,主打跨学段诊断与交互式教学

RUNTO 数据显示,2025 年中国学习平板市场全渠道销量达 632.1 万台,同比增长 6.7%。在此市场需求背景下,科大讯飞推出新款AI 学习机 T90 Pro。有别于直接输出计算结果的通用大模型,该设备侧重于学习过程的探究与启发,通过整合学情诊断、辅导教学与反馈激励环节,构建系统化的个性化学习链路。

作为垂直领域的教育硬件,该款学习机的核心功能主要围绕以下三个维度展开:

  • 跨学段学情诊断:设备内置覆盖全国 32 个省级行政区的区域化知识图谱,支持跨年级追溯并定位知识薄弱点。据测试数据,使用该功能进行同章节查漏补缺时,学习耗时可减少 64%,学会率提升 3.1 倍。
  • 交互式辅助教学:搭载名为「晓悦」的 AI 辅导模块。在处理错题时,系统不直接提供最终答案,而是先分析具体的个性化错因,随后通过板书式的互动引导,辅助学生理解相关考点。
  • 学习反馈与管理机制:结合教育心理学理论对学习反馈系统进行设计,在完成练习后提供详尽的具体评价。此外,设备配备的「小飞 AI 学伴」可协助整理错题、报听写,并提供日常的倾听与陪伴功能

该产品的底层技术壁垒依托于科大讯飞在教育领域 22 年的数据沉淀与行业经验。其业务服务覆盖全国超 5 万所学校,并与北师大、华东师大等学术团队开展了深度合作,例如设备内采用的 AI 作文批改技术即与中高考阅卷系统同源。通过将人工智能技术与教育垂直领域的专业知识相融合,科大讯飞在市场端保持了稳定的份额,数据显示其已连续五年位居高端学习机销售额与销量首位。

(@量子位)

4、AI 儿童故事平台 Giant 获 800 万美元融资,AI 对话时长破百万分钟

近日,面向儿童的 AI 互动故事平台 Giant 宣布完成 800 万美元种子轮融资。本轮融资由 Matrix、Decasonic 与 Griffin Gaming Partners 联合领投,Perceptive Ventures 等多家机构跟投。该笔资金将主要用于扩展其互动故事平台。

Giant 成立于 2025 年 5 月,由连续创业者约翰·科布斯(John Kobs)创办。科布斯表示,创办初衷是希望研发一款让孩子从内容消费者转变为创造者的产品。在当前的数字环境中,Giant 试图提供一个安全可靠的空间,用以培养孩子的想象力并塑造品格,让儿童不只是观看故事,而是亲身融入故事之中

目前,该平台主要具备以下三项核心功能:

  • 专属形象生成:可根据儿童的实际照片生成对应的专属卡通人物。
  • 个性化剧集定制:支持孩子自主创作故事情节,并观看以自己名字和兴趣为特色的专属动画。
  • 智能实时互动:支持儿童与故事中的 AI 角色展开直接对话。

运营数据方面,自上线以来,Giant 平台内儿童与 AI 角色的对话总时长已突破 100 万分钟,累计制作个性化剧集超过 20 万集。投资方认为,该产品将儿童创造力的第一性原理与人工智能技术相结合,正在定义一个由 AI 驱动的创意故事讲述新类别。

(@多知)

5、OpenAI 探索成人语音与文本交互:ChatGPT 试水「Naughty Chats」,需自拍验证年龄以规避合规风险

据 Android Authority 挖掘最新的 ChatGPT 安卓应用程序更新代码(版本号 v1.2026.055)发现,OpenAI 可能即将推出一项名为「Naughty Chats」的成人内容模式。此举呼应了该公司首席执行官 Sam Altman 去年 10 月关于放宽成人内容限制的预告。

根据隐藏的代码字符串显示,「此设置允许 ChatGPT 在用户提问时使用更大胆、成人主题的语言」。关于该模式的运行机制,目前透露出以下核心信息:

  • 严格的年龄门槛与验证:该功能仅面向 18 岁及以上用户开放,并要求进行强制年龄验证。OpenAI 近期引入了年龄预测工具,会通过账户活跃时长、常见使用时段、填写的年龄以及其他使用习惯来判定用户年龄的真实性。若未通过该验证,用户将被转入青少年模式。若需进一步确认,用户须通过第三方机构 Persona 上传自拍照完成验证。
  • 主动开启机制:符合 Altman 此前的表态,这种对成人内容友好的模式不会默认启用,只有在用户主动提出要求并开启后才会激活。

目前,该功能似乎仍处于开发阶段,代码中尚未提供明确的激活方式。在当前的人工智能领域,部分其他平台已允许使用成人主题的语言,但一些竞争对手(如 Grok)也曾因缺乏安全护栏、允许生成真实人物的非自愿色情图像而遭到外界批评。相较而言,OpenAI 在放宽限制的同时,正试图通过年龄验证等手段控制合规风险。

( @PCMag)

03 有态度的观点

1、沃尔玛首席人力官莫里斯:美国劳动力需学习中国,那里 5 岁孩子都在学 DeepSeek

据《财富》杂志报道,美国企业正加速推进 AI 培训,以避免劳动力在技术变革中落后。德勤、Verizon 和沃尔玛等大型企业均已启动大规模员工培训计划。

沃尔玛首席人力官唐娜 · 莫里斯在接受《财富》采访时表示,这种趋势不仅关系到企业自身,更关系到美国整体经济竞争力:「看看中国,5 岁的孩子就开始学习 DeepSeek,显而易见,中国对能力建设有多重视。如果美国也全面推动 AI 能力建设,将对经济产生深远影响。」

中国正在系统性推进 AI 教育。北京已要求中小学每学年至少提供 8 小时 AI 课程,内容涵盖聊天机器人使用和 AI 伦理等主题。中国学生整体在校学习时间也普遍高于美国学生。

报道还指出,中国的教育投入正在转化为人才优势。保尔森研究所 2020 年研究显示,全球近三分之一顶级 AI 人才出生于中国,美国科技公司正以高薪争夺这些人才。譬如,Meta 去年 6 月成立 Superintelligence Labs 时,11 名研究人员中有 7 人出生于中国,且全部从美国境外招募。

据 IT 之家了解,美国企业界正日渐将 AI 教育视为战略重点。去年,包括微软 CEO 萨蒂亚 · 纳德拉、DoorDash CEO 徐迅以及 Airbnb CEO 布莱恩 · 切斯基在内的 400 多位企业负责人联名致信美国立法者,呼吁将计算机科学和 AI 纳入所有学生的基础课程体系。「在 AI 时代,我们必须让孩子成为 AI 创造者,而不仅是使用者。计算机科学和 AI 基础是帮助学生在技术时代取得成功的关键,否则将面临落后的风险。」

莫里斯认为,缩小 AI 人才差距的关键在于企业主动投资员工培训:「大型雇主必须积极帮助员工适应 AI 驱动和数字化的工作环境。如果所有企业共同投入培训,整体劳动力竞争力将显著提升。」

她还指出,AI 培训适用于几乎所有岗位:「AI 的独特之处在于它几乎不受岗位限制。不同岗位使用 AI 的方式可能不同,但所有人都应具备这方面的能力。」

(@IT 之家)

04 有看点的活动

1、Open Claw 碰撞场:来北京五道口,和 AI 大佬们一起「碰」出点东西

阅读更多 Voice Agent 学习笔记:了解最懂 AI 语音的头脑都在思考什么

写在最后:

我们欢迎更多的小伙伴参与 「RTE 开发者日报」 内容的共创,感兴趣的朋友请通过开发者社区或公众号留言联系,记得报暗号「共创」。

对于任何反馈(包括但不限于内容上、形式上)我们不胜感激、并有小惊喜回馈,例如你希望从日报中看到哪些内容;自己推荐的信源、项目、话题、活动等;或者列举几个你喜欢看、平时常看的内容渠道;内容排版或呈现形式上有哪些可以改进的地方等。

作者提示: 个人观点,仅供参考

OPPO A55 Color13 还可以刷机吗。有无教程,最后测试机 iPhone 寿终就请了,公司给了台 oppo 还没 root,不知道怎么弄,很久没玩过这些了

我们是 SportVision ,一家专注 AI + 运动科技的极客创业团队。
💰 资金拉满:已获大疆教父李泽湘教授 + 高瓴资本投资
👥 核心大牛:主创来自腾讯、字节、大疆、mmlab 、哥大/交大校友。
我们正在做一件颠覆网球/匹克球体验的超酷产品—— 一台架在球场上的 AI 智能相机 🎥
🚀 现在核心团队火速扩军

🔥 我们在找谁?(坐标:深圳)
1️⃣ 嵌入式系统工程师 (SE)⚡:主导端侧架构,大疆/影石背景速来!
2️⃣ 嵌入式多媒体工程师🎬:搞定音视频流,稳如老狗。
3️⃣ 姿态识别算法工程师🤖:CV 大牛,教 AI 看懂网球动作。
4️⃣ 小目标追踪算法工程师🎯:死磕 200km/h 高速网球轨迹。
5️⃣ AI 应用架构师 (Edge)🧠:端侧芯片算力上的性能魔术师。
6️⃣ 产品营销负责人📈:从 0 到 1 打造品牌。

🎁 你能得到什么?
💰 顶级机构加持的充足资金 + 早期核心成员股权/期权激励。
🚀 经历一个硬件 + AI 产品从 0 到 1 走向全球的爽感。
🎾 如果你也是网球狂热粉,这里绝对是你的梦中情司!工作打球两不误!

☎️ 联系方式:微信 kris-never-stop

五大主流CRM品牌深度横评:从外勤到集团管控的全场景能力对决

在企业数字化转型的浪潮中,CRM系统已从“客户信息存储工具”升级为“全流程业务引擎”,覆盖外勤销售效率提升、客户全生命周期运营、集团级权限管控、 销售自动化 (SFA)、移动办公五大核心场景。本文选取超兔一体云、Freshworks、用友CRM、Microsoft Dynamics 365、 SAP五大主流品牌,从专业维度展开深度对比,为企业选型提供决策依据。

一、对比框架与核心评估指标

本次对比围绕外勤销售、客户管理、集团权限管理、SFA、移动端APP五大维度,每个维度拆解为业务价值、核心评估指标、 品牌差异化 功能三层逻辑,确保分析的深度与针对性。

二、五大品牌核心能力横向对比

(一)核心能力总览表

为直观呈现差异,先通过表格汇总五大品牌的关键功能:

维度超兔一体云Freshworks用友 CRMMicrosoft Dynamics 365SAP
外勤销售数据采集(语音/拍照/定位)、任务提醒、路线规划、实时协作、自动同步多终端同步、客户数据访问、Freshchat集成现场录入、轨迹追踪、巡店管理、任务自动分配、拜访规则自定义客户位置标注、路线优化、Outlook/Teams集成(会议关联客户)多语言全球部署、流程合规、海外团队适配
客户管理多渠道获取(百度/抖音/官网)、工商/天眼查补全、模糊查重、客池全生命周期分类360°视图(邮件/电话/聊天)、Freddy AI自动化、销售-服务-售后联动全生命周期(潜在→流失)、360°视图、聚类/信用管理、查重验真互动数据自动同步、微软生态(Office 365/Power BI)共享ERP深度集成(销售→生产→财务)、全链路数据打通
集团权限管理九级组织支持、全局自动权限(上级管下级)、字段级自定义+功能白名单基础角色/部门权限、企业版定制字段级权限、直分销协同、多组织架构适配多角色分级、大型企业架构适配跨国/多级权限、跨部门实时共享、流程标准化严格
SFA流程自动化、多跟单模型(小单/项目)、销售漏斗+多表聚合分析销售序列(自定义漏斗)、可视化管道、线索自动分配全流程自动化(线索→回款)、销售漏斗可视化、LTC(与ERP闭环)流程自动化、ERP/财务联动、项目型销售适配流程合规、复杂报价(CPQ)、制造/重工业场景适配
移动端APP全功能集成(外勤/客户/跟单)、离线操作、数据加密多终端同步、Freshchat集成、移动办公iOS/Android双端、微信/WEB支持、离线同步、流程审批全功能APP、离线操作、移动审批、微软生态无缝切换多语言、流程合规、海外团队适配

(二)维度1:外勤销售——从“流程合规”到“效率倍增”

外勤销售的核心是解决“数据实时性、任务可控性、团队协作”三大痛点,关键评估指标包括:数据采集能力、任务管理、路线规划、实时协作

1. 超兔一体云:全链路闭环的外勤解决方案

超兔的外勤功能围绕“数据从现场到云端的无缝流动”设计:

  • 数据采集:支持语音输入、拍照(如设备使用场景记录)、定位打卡,覆盖外勤全场景;
  • 任务管理:系统自动分配任务(含客户信息、时间、地点),提前1天提醒;
  • 路线规划:根据客户分布优化拜访顺序,内置导航引导;
  • 实时协作:销售人员可通过APP向团队求助,共享客户信息,解决现场问题。 优势:数据自动同步+实时协作,彻底避免“外勤数据滞后”问题。
2. 用友CRM:零售场景的精细化拜访管理

用友的外勤功能聚焦“巡店/铺货”等零售场景:

  • 支持现场录入客户信息(如库存/陈列状态)、拜访轨迹追踪(确保拜访真实性);
  • 可自定义拜访规则(如每周2次巡店),自动分配后续任务(如跟进铺货问题)。 优势:贴合本土零售企业的“外勤标准化”需求。
3. Microsoft Dynamics 365:生态联动的智能外勤

依托微软生态,Dynamics 365的外勤功能强调“客户互动与办公的融合”:

  • 客户位置标注在地图上,自动优化拜访顺序;
  • 与Outlook/Teams深度集成,会议可自动关联客户档案,避免“会议与客户信息割裂”。 优势:适合已使用微软生态(Office 365)的企业,无缝切换。
4. Freshworks:轻量级多终端同步

Freshworks的外勤功能聚焦“多终端数据一致性”:

  • 支持手机/电脑同步客户数据,销售人员可随时访问客户档案;
  • 与Freshchat(即时聊天)集成,现场可直接回复客户消息。 局限:缺乏路线规划、轨迹追踪等深度功能。
5. SAP:全球部署的流程合规

SAP的外勤功能针对海外团队设计:

  • 支持多语言,适配不同国家的合规要求(如欧洲GDPR);
  • 移动端功能聚焦“流程合规”(如拜访记录必须填写合规字段)。 优势:适合跨国企业的海外外勤团队,确保全球流程一致。

(三)维度2:客户管理——从“信息存储”到“全生命周期运营”

客户管理的核心是解决“信息孤岛、数据不准确、生命周期断裂”三大问题,关键评估指标包括:多渠道获取、信息整合、查重验真、全生命周期管理

1. 超兔一体云:多渠道+强整合的客户运营

超兔的客户管理以“多渠道获客+数据自动补全”为核心:

  • 多渠道获取:支持百度广告、抖音巨量引擎、官网落地页、微信/小程序、地推等全渠道客户抓取,自动录入系统;
  • 信息整合:自动补全客户工商信息、天眼查数据,生成用户画像(如购买历史+沟通记录);
  • 查重验真:客户名/手机号/简称模糊查重(如“XX科技”与“XX信息技术”自动识别为同一客户),避免重复录入;
  • 生命周期管理:按跟进状态自动分类为“需求培养→有需求→成功”客池,对应不同跟进策略。 优势:从“获客”到“转化”的全链路数据闭环,适合需要“精准获客”的企业。
2. 用友CRM:本土企业的全生命周期覆盖

用友的客户管理聚焦“本土企业的实际场景”:

  • 全生命周期:覆盖“潜在客户→准入→变动→流失”全流程,支持“客户召回”等流失管理;
  • 360°视图:整合基础信息、交互记录(如通话/邮件)、商机状态、历史交易、关键人信息,避免“销售只看自己的客户”;
  • 信用管理:支持客户信用评级,避免“欠款风险”。 优势:适合需要“全流程客户管控”的本土大型企业。
3. Freshworks:销售-服务联动的客户体验

Freshworks的客户管理依托“多产品生态”:

  • 360°视图:整合邮件、电话、Freshchat(即时聊天)等互动数据,统一存储客户信息;
  • Freddy AI:通过AI实现自动化互动(如个性化跟进提醒、客户响应),提升满意度;
  • 多产品联动:与Freshdesk(客户服务)、Freshcaller(云呼叫中心)集成,覆盖“销售→服务→售后”全流程。 优势:适合需要“销售与服务协同”的企业(如 SaaS/电商)。
4. Microsoft Dynamics 365:生态共享的客户数据

依托微软生态,Dynamics 365的客户管理强调“数据的实时共享”:

  • 自动同步邮件、通话记录等互动数据,与Office 365、Power BI集成,支持“客户数据+办公数据”的联合分析;
  • 适合已使用微软产品的企业,避免“跨系统数据搬运”。
5. SAP:ERP联动的全链路客户数据

SAP的客户管理核心是“与ERP的深度集成”:

  • 客户数据从“销售”延伸至“生产→财务”(如客户订单直接触发生产计划),避免“销售与生产脱节”;
  • 适合制造/重工业企业,需要“销售与供应链联动”的场景。

(四)维度3:集团权限管理——从“角色隔离”到“多组织协同”

集团权限管理的核心是解决“多组织架构下的数据安全与协同”问题,关键评估指标包括:组织架构支持、权限粒度、自动机制

1. 超兔一体云:全局自动权限的标杆

超兔的权限管理采用“全局自动权限机制”,完美适配集团型企业:

  • 组织架构支持:支持九级人员结构(如集团→子公司→部门→小组),覆盖矩阵式/项目组等复杂架构;
  • 权限粒度:上级管理下级(如销售经理可看下属客户)、同级互相隔离(如A组无法看B组客户)、助理跟随主管(助理可访问主管的客户);
  • 自定义权限:支持功能白名单(如财务只看客户财务数据)、字段级权限(如隐藏客户手机号)。 优势:无需手动配置,系统自动适配组织架构,适合“快速扩张”的集团企业。
2. 用友CRM:字段级的精细化管控

用友的权限管理聚焦“本土集团的精细化需求”:

  • 支持字段级权限(如隐藏客户财务数据)、部门级权限(如子公司只能看自己的客户);
  • 适配直分销业务(如总部与经销商的订单同步),确保跨组织数据协同。
3. SAP:跨国集团的权限标准

SAP的权限管理针对“跨国/多级集团”:

  • 支持跨部门数据实时共享(如欧洲子公司的客户数据同步至中国总部);
  • 流程标准化严格,确保全球各分支的权限一致(如 GDPR 合规)。
4. Freshworks:基础角色的权限隔离

Freshworks的权限管理为基础角色/部门级(如销售部门不能看财务数据),适合中小微企业;复杂集团架构需定制企业版。

(五)维度4:SFA(销售自动化)——从“手动跟进”到“智能驱动”

SFA的核心是解决“销售流程不标准、转化率低、数据难分析”问题,关键评估指标包括:流程自动化、智能跟单、数据分析

1. 超兔一体云:多场景的智能跟单

超兔的SFA围绕“不同业务场景”设计:

  • 流程自动化:预设销售漏斗(如“线索→跟进→成交”),系统自动推进交易状态;
  • 多跟单模型:支持“小单快单”(如零售)、“商机跟单”(如项目型销售)、“多方项目”(如跨部门协作);
  • 数据分析:提供销售漏斗(各阶段转化率)、同比环比(业绩增长)、多表聚合(如客户来源+转化率)等报表,支撑决策。 优势:覆盖“快消/零售/项目型”等多场景,适合需要“灵活跟单”的企业。
2. 用友CRM:LTC全流程闭环

用友的SFA聚焦“从线索到回款”的全流程自动化:

  • 支持线索批量导入→自动分配→跟进→商机→订单→回款的全链路自动化;
  • 与ERP集成,实现“销售订单→生产→财务”的闭环,避免“数据断层”。 优势:适合需要“全流程管控”的制造/工程企业。
3. Microsoft Dynamics 365:项目型销售的利器

Microsoft的SFA适合“项目型销售”(如软件实施、工程):

  • 与ERP/财务系统联动,支持“项目阶段管理”(如需求调研→开发→验收);
  • 可视化销售管道,快速定位“项目 bottleneck”(如某阶段转化率低)。

(六)维度5:移动端APP——从“功能覆盖”到“体验优化”

移动端APP是外勤/销售团队的“作业终端” ,关键评估指标包括:功能集成度、离线支持、安全性能

1. 超兔一体云:全功能的移动办公平台

超兔的移动端APP集成了所有核心功能

  • 支持外勤销售(任务/路线/数据采集)、客户管理(查看/编辑客户)、跟单中心(商机跟进)、合同订单管理;
  • 支持离线操作(无网络时可记录信息,联网后自动同步);
  • 采用数据加密技术,确保移动数据安全。
2. 用友CRM:本土场景的移动适配

用友的移动端APP覆盖本土企业的移动需求

  • 支持iOS/Android双端,兼容微信/WEB端;
  • 核心功能包括:客户/商机管理、外勤拜访(轨迹追踪)、流程审批(如订单审核)、数据同步。
3. Microsoft Dynamics 365:生态无缝切换

依托微软生态,Dynamics 365的移动端APP与Office 365/Teams无缝集成

  • 支持离线操作(如查看客户数据)、移动审批(如请假/订单);
  • 适合已使用微软产品的企业,无需额外学习成本。

三、品牌能力雷达图与选型建议

为量化各品牌的综合能力,我们通过雷达图(1-5分,5分为满分)呈现差异:

品牌外勤销售客户管理集团权限SFA移动端综合评分
超兔一体云4.54.84.74.64.54.62
用友CRM4.24.64.54.44.34.40
Microsoft Dynamics 3654.34.44.24.54.44.36
SAP4.14.34.84.34.14.32
Freshworks4.04.53.54.24.04.04

选型建议:

  1. 需要“精准获客+外勤闭环”的企业:选超兔一体云(多渠道获客+外勤数据同步+集团权限);
  2. 本土大型企业/零售场景:选用友CRM(全生命周期+零售巡店+字段级权限);
  3. 已使用微软生态的企业:选Microsoft Dynamics 365(无缝集成+项目型销售);
  4. 跨国/重工业企业:选SAP(全球部署+ERP联动+流程合规);
  5. 中小微企业/销售-服务协同:选Freshworks(多产品生态+易上手)。

四、总结:CRM选型的核心逻辑

企业选型CRM的本质是“匹配自身业务场景”:

  • 若需“从获客到转化的全链路闭环”,选超兔;
  • 若需“本土零售/集团管控”,选用友;
  • 若需“跨国/ERP联动”,选SAP;
  • 若需“微软生态协同”,选Microsoft;
  • 若需“小而美”的销售-服务协同,选Freshworks。

最终,没有“最好的CRM”,只有“最适合自己的CRM” ——企业需结合自身规模、行业、业务场景,选择能覆盖核心痛点的解决方案。

(注:文中功能相关描述均基于公开披露信息,具体功能服务以厂商实际落地版本为准。)

从周六开始,我突然就莫名情绪低落,感觉非常压抑,一开始以为是「长假综合征」,直到周日躺了一天才想明白:心结不在工作状态,而是被引发了强烈的 「道德不适感」

查了一下资料:「道德不适感」在心理学上的对应概念应该叫做 「道德困扰 (Moral Distress)」,不过我还是继续按照自己的习惯来写。

这两天国际新闻很清楚:美国与以色列在和伊朗谈判的同时,秘密发动军事突袭。袭击发生前一天,双方还释放积极信号,宣称谈判取得突破。而伊朗最高领导层正在开会,商议谈判后续策略,遭到精准突袭,被「斩首」成功。

这件事,无论从规则、道义、底线等哪个维度来看,都是极其恶劣的行径:

  • 以和谈为掩护,欺骗对手,一边谈一边备战,用外交信号掩盖战争意图;
  • 不宣而战,直接突袭,违背国际法与基本的战争法准则;
  • 击杀主权国家最高领导人,其本质根本就是政治暗杀,不是正规作战。

这就相当于:两军摆开阵势,约定最终和谈,高喊「两军交战不斩来使」,对方主将如约赴会,结果被冷箭射中,大军随即掩杀。这不是堂堂之战,而是彻头彻尾的欺诈与偷袭。

放到中国历史里对照,最接近的就是 「洛水之誓」。三国之前尚讲「义战」,双方对垒也有底线与信用;结果司马氏背信弃义,在曹氏投降后斩尽杀绝,彻底摧毁政治信任,开启了更黑暗的时代。今天美国和以色列的做法,性质等同,透支的是国际社会最基本的信任,迟早会遭到反噬。

至此,我找到了自己情绪压抑的根源,这种道德不适感来自于 「光天化日之下,有人做了卑劣的事情,却没有受到惩罚」,来自于 「亲眼看到违背道德与正义的行为,却无力制止」

正如那句话:「人的一切痛苦,本质上都是对自己无能的愤怒」

我们能看清是非,能判断善恶,但作为个体,却没有能力改变大国博弈的结果。这种清醒的无力感,就是道德不适感。

但无力,不代表要放下内心的标尺。

难道因为暂时做不了什么,就视而不见?甚至反过来为美国和以色列的「强盗逻辑」辩护?当然不! 守住自己的道德底线,不因为现实残酷就同流合污,这是最基本的坚持。 是非对错交给时间,历史自有清算。

这件事,也给我们三个很现实的启示:

第一,永远不要高估对手的道德底线。安全、主动权、核心能力,必须牢牢抓在自己手里。做最坏的打算,做最足的准备,才是生存之道。

第二,投降主义注定没有好结果。伊朗的教训很真实,一味妥协、左右摇摆,换不来尊重,只会换来变本加厉的打压。网上说得很形象 —— 伊朗就是 「一边吃屎,一边挨鞭子」。战略不坚定,战术再努力也没用。

第三,这是美帝国主义的最后疯狂。越是接近历史拐点,越会无所顾忌撕下伪装,毫无底线、不择手段。把最真实的强盗嘴脸暴露在全世界面前,恰恰说明它正在失去人心、失去秩序主导权。

不是不报,时候未到。

还不到亲自下场的时候,我们暂时能做的是,保持清醒、守住底线、做好自己、静静观望。

自己用鞭炮战法,每天一般能吃到 1-2 个点的目标收益,然后就退出来不看了。
在想有没有好的办法自动交易?比如网格交易或者量化模型,有没有老哥懂的,免 5 万 0.5etf 手续费,感觉高频交易手续费基本忽略不计,可以搞个 10-20 万这样运行起来。

Rivet 推出的 Sandbox Agent SDK 提供了一个用于构建编程代理的通用 API,使开发者能够在不同的代理运行时(如 Claude Code、Codex、OpenCode 和 Amp)之间切换,而无需为每种运行时分别重写集成逻辑。该 SDK 旨在解决长期以来困扰开发者的代理 API 碎片化、会话管理差异以及流式数据格式不统一等问题,这些问题使得代理集成复杂且难以维护。

 

Rivet 联合创始人兼 CTO Nathan Flurry 表示,构建具备自主能力的代理系统主要面临三大挑战:API 碎片化、临时状态问题,以及不同服务提供商之间的部署差异。

 

构建编程代理并不容易。Claude Code 有一套 API,Codex 有另一套,OpenCode 和 Amp 也各自采用不同方式。即使只选择其中一个,你仍然要面对会话状态在进程崩溃时丢失的问题、为每个沙箱提供商编写不同的集成代码,以及无法将会话记录以流式方式返回到应用程序等挑战。

 

每个代理都有自己的一套事件格式、会话模型和权限体系。例如,Claude Code 通过 stdout 输出 JSONL 格式的数据,而 Codex 使用 JSON-RPC。这意味着开发者不得不为两者分别构建不同的集成逻辑。部署层面也增加了复杂性,像 Daytona、Vercel 和 E2B 这样的平台都提供各自定制的 API。

 

相比之下,Rivet 的 Sandbox Agent SDK 允许开发者针对一个统一 API 编写集成代码,只需修改配置即可切换不同代理。这段简单的代码展示了如何用 SDK 创建代理对话:

import { SandboxAgent } from "sandbox-agent";const client = await SandboxAgent.start();await client.createSession("my-session", {  agent: "claude",  // or "codex", "opencode", "amp"  permissionMode: "auto",});for await (const event of client.streamEvents("my-session")) {  console.log(event.type, event.data);}
复制代码

 

该 SDK 还配套统一的会话数据结构。所有与代理相关的事件(包括会话生命周期、流式输出、人工介入提问、工具执行审批以及错误信息)都遵循一致的格式,从而避免为适配不同代理输出而编写大量定制逻辑。

 

在 X.com 上这篇发布的评论区中,Gianfranco P. 表示

这是编程代理生态系统迫切需要的一层抽象。API 碎片化确实是构建 AI 驱动开发工具时的一个痛点。一次集成,通过修改配置就能切换代理 —— 这简直是测试哪种模型表现最佳的理想方式。

 

一位 Hacker News 读者询问,是否可以将 Rivet 的 Sandbox Agent SDK 理解为“基于HTTP 的 ACP(agent client protocol)”。Flurry 解释说,这种类比在大方向上是准确的,但 ACP 更侧重于为编辑器场景所需的那部分功能提供统一 API,而 Sandbox Agent SDK 的能力更加全面,重点在于支持完整的代理自动化。

 

Sandbox Agent SDK 是一个轻量级的 15MB 静态二进制文件,使用 Rust 编写,没有运行时依赖。它可以安装在任何能够执行 Linux 二进制文件的环境中,包括 Daytona、E2B、Vercel Sandboxes、Docker 等。该项目目前已在 GitHub 上开源

原文链接:

https://www.infoq.com/news/2026/02/rivet-agent-sandbox-sdk/

翻了一下官网的发货时间

MacBookPro 和 MacMini 的发货时间延迟

大概率还有一款新的 MacBook A18pro

其他的机型都是正常发货的,MacBookAir 、MacStudio 和 MacPro 可能都不会更新

本文为墨天轮数据库管理服务团队第169期技术分享,内容原创,作者为技术顾问胡振兴,如需转载请联系小墨(VX:modb666)并注明来源。如需查看更多文章可关注【墨天轮】公众号。

image.png

一、安装前准备

1.1 集群规划

主库备库
业务 IP192.168.6.142192.168.6.143
实例名DMGRID1DMGRID2
实例端口52365236
MAL 端口53365336
MAL 守护进程端口54365436
守护进程端口55365536
OGUID4533145331
守护组GRP1GRP1
安装目录/dm8/dmdbms/dm8/dmdbms
实例目录/dm8/dmdbms/data/dm8/dmdbms/data
归档上限5120051200

1.2 集群架构

搭建的主备集群架构如下图:

图片

1.3 切换模式说明

image.png

ARCH\_WAIT\_APPLY 参数,设置为 0:高性能模式;设置为 1:事务一致模式。

  • 故障手动切换情境下 ARCH\_WAIT\_APPLY 只能为 0。故障自动切换情境下 ARCH\_WAIT\_APPLY 可以为 0,也可以为 1。
  • ARCH\_WAIT\_APPLY 参数设置的判断依据为业务是否要查询备机最新数据。如果需要,则配置为 1(较大性能衰减);如果不需要,则配置为 0

二、集群搭建

2.1 配置 主库

2.1.1 初始化实例并备份数据

初始化实例

[dmdba@dm1 ~]$ /dm8/dmdbms/bin/dminit PATH=/dm8/dmdbms/data/ INSTANCE_NAME=DMGRID1 PAGE_SIZE=32 EXTENT_SIZE=32 CASE_SENSITIVE=y DB_NAME=DAMENG INSTANCE_NAME=DMGRID1 PORT_NUM=5236 LOG_SIZE=2048 SYSDBA_PWD=Oracle2025! SYSAUDITOR_PWD=Oracle2025!
  • 启动服务
  • /dm8/dmdbms/bin/dmserver /dm8/dmdbms/data/DAMENG/dm.ini

图片

开启归档

SQL> ALTER DATABASE MOUNT;
SQL> ALTER DATABASE ARCHIVELOG;
SQL> ALTER DATABASE ADD ARCHIVELOG 'DEST=/dm8/dmdbms/data/DAMENG/arch, TYPE=LOCAL, FILE_SIZE=1024, SPACE_LIMIT=51200';
SQL> ALTER DATABASE OPEN;
  • 备份数据
  • SQL> BACKUP DATABASE BACKUPSET '/dm8/dmdbms/data/DAMENG/bak/BACKUP\_FILE';

图片

修改 dm.ini

SQL> SP_SET_PARA_VALUE (2,'PORT_NUM',5236);
SQL> SP_SET_PARA_VALUE (2,'DW_INACTIVE_INTERVAL',60);
SQL> SP_SET_PARA_VALUE (2,'ALTER_MODE_STATUS',0);
SQL> SP_SET_PARA_VALUE (2,'ENABLE_OFFLINE_TS',2);
SQL> SP_SET_PARA_VALUE (2,'MAL_INI',1);
SQL> SP_SET_PARA_VALUE (2,'RLOG_SEND_APPLY_MON',64);

关闭前台实例服务 Ctrl+C

2.1.2 修改 dmarch.ini

[dmdba@dm1 ~]$ vi /dm8/dmdbms/data/DAMENG/dmarch.ini

ARCH_WAIT_APPLY = 0 #0:高性能 1:事务一致
[ARCHIVE_LOCAL]
ARCH_TYPE = LOCAL #本地归档类型
ARCH_DEST = /dm8/dmdbms/data/DAMENG/arch/ #本地归档存放路径
ARCH_FILE_SIZE = 1024 #单个归档大小,单位 MB
ARCH_SPACE_LIMIT = 51200 #归档上限,单位 MB
[ARCHIVE_REALTIME1]
ARCH_TYPE = REALTIME #实时归档类型
ARCH_DEST = DMGRID2 #实时归档目标实例名

2.1.3 创建 dmmal.ini

[dmdba@dm1 ~]$ vi /dm8/dmdbms/data/DAMENG/dmmal.ini

MAL_CHECK_INTERVAL = 10 #MAL 链路检测时间间隔
MAL_CONN_FAIL_INTERVAL = 10 #判定 MAL 链路断开的时间
MAL_TEMP_PATH = /dm8/dmdbms/data/malpath/ #临时文件目录
MAL_BUF_SIZE = 512 #单个 MAL 缓存大小,单位 MB
MAL_SYS_BUF_SIZE = 2048 #MAL 总大小限制,单位 MB
MAL_COMPRESS_LEVEL = 0 #MAL 消息压缩等级,0 表示不压缩
[MAL_INST1]
MAL_INST_NAME = DMGRID1 #实例名,和 dm.ini 的 INSTANCE_NAME 一致
MAL_HOST = 192.168.6.142 #MAL 系统监听 TCP 连接的 IP 地址
MAL_PORT = 5336 #MAL 系统监听 TCP 连接的端口
MAL_INST_HOST = 192.168.6.142 #实例的对外服务 IP 地址
MAL_INST_PORT = 5236 #实例对外服务端口,和 dm.ini 的 PORT_NUM 一致
MAL_DW_PORT = 5436 #实例对应的守护进程监听 TCP 连接的端口
MAL_INST_DW_PORT = 5536 #实例监听守护进程 TCP 连接的端口
[MAL_INST2]
MAL_INST_NAME = DMGRID2
MAL_HOST = 192.168.6.143
MAL_PORT = 5336
MAL_INST_HOST = 192.168.6.143
MAL_INST_PORT = 5236
MAL_DW_PORT = 5436
MAL_INST_DW_PORT = 5536

2.1.4 创建 dmwatcher.ini

[dmdba@dm1 ~]$ vi /dm8/dmdbms/data/DAMENG/dmwatcher.ini

[GRP1]
DW_TYPE = GLOBAL #全局守护类型
DW_MODE = AUTO #MANUAL:故障手切 AUTO:故障自切
DW_ERROR_TIME = 20 #远程守护进程故障认定时间
INST_ERROR_TIME = 20 #本地实例故障认定时间
INST_RECOVER_TIME = 60 #主库守护进程启动恢复的间隔时间
INST_OGUID = 45331 #守护系统唯一 OGUID 值
INST_INI = /dm8/dmdbms/data/DAMENG/dm.ini #dm.ini 文件路径
INST_AUTO_RESTART = 1 #打开实例的自动启动功能
INST_STARTUP_CMD = /dm8/dmdbms/bin/dmserver #命令行方式启动
RLOG_SEND_THRESHOLD = 0 #指定主库发送日志到备库的时间阈值,默认关闭
RLOG_APPLY_THRESHOLD = 0 #指定备库重演日志的时间阈值,默认关闭

2.1.5 拷贝备份文件

拷贝备份文件到备库

[dmdba@dm1 fullback]$ scp * dmdba@192.168.6.143:/dmdata/dm8/backup

图片

2.1.6 注册服务

[root@~]# /dm8/dmdbms/script/root/dm_service_installer.sh -t dmserver -p DMGRID1 -dm_ini /dm8/dmdbms/data/DAMENG/dm.ini -m mount
[root@~]# /dm8/dmdbms/script/root/dm_service_installer.sh -t dmwatcher -p Watcher -watcher_ini /dm8/dmdbms/data/DAMENG/dmwatcher.ini

图片

2.2 配置 备库

2.2.1 初始化实例

图片

2.2.2 恢复数据

/dm8/dmdbms/bin/dmrman CTLSTMT="RESTORE DATABASE '/dm8/dmdbms/data/DAMENG/dm.ini' FROM BACKUPSET '/dm8/dmdbms/data/DAMENG/bak/BACKUP_FILE'"
/dm8/dmdbms/bin/dmrman CTLSTMT="RECOVER DATABASE '/dm8/dmdbms/data/DAMENG/dm.ini' FROM BACKUPSET '/dm8/dmdbms/data/DAMENG/bak/BACKUP_FILE'"
/dm8/dmdbms/bin/dmrman CTLSTMT="RECOVER DATABASE '/dm8/dmdbms/data/DAMENG/dm.ini' UPDATE DB_MAGIC"

2.2.3 替换 dmarch.ini

[dmdba@dm2 DAMENG]$ vi /dm8/dmdbms/data/DAMENG/dmarch.ini
ARCH_WAIT_APPLY = 0 #0:高性能 1:事务一致
[ARCHIVE_LOCAL]
ARCH_TYPE = LOCAL #本地归档类型
ARCH_DEST = /dm8/dmdbms/data/DAMENG/arch/ #本地归档存放路径
ARCH_FILE_SIZE = 1024 #单个归档大小,单位 MB
ARCH_SPACE_LIMIT = 51200 #归档上限,单位 MB
[ARCHIVE_REALTIME1]
ARCH_TYPE = REALTIME #实时归档类型
ARCH_DEST = DMGRID1 #实时归档目标实例名

2.2.4 配置 dm.ini、dmmal.ini 和 dmwatcher.ini

在 备库机器上配置备库的实例名为 DMGRID2,dm.ini 参数修改如下

INSTANCE_NAME = DMGRID2
PORT_NUM = 5236 #数据库实例监听端口
DW_INACTIVE_INTERVAL = 60 #接收守护进程消息超时时间
ALTER_MODE_STATUS = 0 #不允许手工方式修改实例模式/状态/OGUID
ENABLE_OFFLINE_TS = 2 #不允许备库 OFFLINE 表空间
MAL_INI = 1 #打开 MAL 系统
ARCH_INI = 1 #打开归档配置
RLOG_SEND_APPLY_MON = 64 #统计最近 64 次的日志重演信息

配置 dmmal.ini 和 dmwatcher.ini

备库 机器里 dmmal.ini、dmwatcher.ini 与 主库 DMGRID2 的 dmmal.ini、dmwatcher.ini 相同,参照 A 机器 dmmal.ini、dmwatcher.ini 文件进行配置

2.2.5 注册服务
/dm8/dmdbms/script/root/dm_service_installer.sh -t dmserver -p DMGRID2 -dm_ini /dm8/dmdbms/data/DAMENG/dm.ini -m mount
/dm8/dmdbms/script/root/dm_service_installer.sh -t dmwatcher -p Watcher -watcher_ini /dm8/dmdbms/data/DAMENG/dmwatcher.ini
若要删除自启,可利用如下方式:
[root@~]# /dm8/dmdbms/script/root/dm_service_uninstaller.sh -n DmServiceDMGRID2
[root@~]# /dm8/dmdbms/script/root/dm_service_uninstaller.sh -n DmWatcherServiceWatcher

2.3 配置确认监视器

2.3.1 创建 dmmonitor.ini

vi /dm8/dmdbms/bin/dmmonitor.ini

MON_DW_CONFIRM = 1 #0:非确认(故障手切) 1:确认(故障自切)
MON_LOG_PATH = ../log #监视器日志文件存放路径
MON_LOG_INTERVAL = 60 #每隔 60s 定时记录系统信息到日志文件
MON_LOG_FILE_SIZE = 512 #单个日志大小,单位 MB
MON_LOG_SPACE_LIMIT = 2048 #日志上限,单位 MB
[GRP1]
MON_INST_OGUID = 45331 #组 GRP1 的唯一 OGUID 值
MON_DW_IP = 192.168.6.142:5436 #IP 对应 MAL_HOST,PORT 对应 MAL_DW_PORT
MON_DW_IP = 192.168.6.143:5436

三、测试主从同步

主库备库都执行

/dm8/dmdbms/bin/dmserver /dm8/dmdbms/data/DAMENG/dm.ini mount

主库

/dm8/dmdbms/bin/disqlsysdba/'"Oracle2025!**"'
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
SP_SET_OGUID(45331);
ALTER DATABASE PRIMARY;
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);

图片

备库

SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
SP_SET_OGUID(45331);
ALTER DATABASE STANDBY;
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
select status$from v$instance;

主库备库启动datawatcher

/dm8/dmdbms/bin/dmwatcher /dm8/dmdbms/data/DAMENG/dmwatcher.ini

查看数据库状态

SQL> select status$,mode$ from v$instance;

图片

备库

图片

主节点启动monitor
/dm8/dmdbms/bin/dmmonitor /dm8/dmdbms/bin/dmmonitor.ini

图片

测试数据同步

create tablespace test datafile '/dm8/dmdbms/data/DAMENG/test.DBF' size 128 autoextend on maxsize 10240;
create user testdb identified by "Oracle2025!" default tablespace test default index tablespace test;
grant dba to testdb;

主节点登录 testdb用户

图片

备节点查询表

[dmdba@dm2 log]$ disql sysdba/'"Oracle2025!"'

图片


墨天轮从乐知乐享的数据库技术社区蓄势出发,全面升级,提供多类型数据库管理服务。墨天轮数据库管理服务旨在为用户构建信赖可托付的数据库环境,并为数据库厂商提供中立的生态支持。
墨天轮数据库服务官网:https://www.modb.pro/service

找了一下原因,给服务器加日志,又是完善 AI 选节点的重试逻辑,最后发现是提示词的问题fake_sad

AI 在找不到 100% 精准匹配的子节点时,由于“星云”这个词在提示词语境中多次出现,当作是兜底的子节点选择了。这种情况只好在提示词中增加严禁指令,比如:禁止生成 "星云"、"其它"、"未分类" 或任何含义模糊的兜底词作为子节点名称。

最近公司扩编得厉害,内推奖励确实香,但作为在里面练习时长两年半的老开发,不打算画大饼,简单分享点真实的打工体感,顺便帮组里捞点靠谱队友。

  1. 关于加班与考勤(不玩虚的)
    这里不是养老院,版本节点该顶还是得顶。但好处是:没有表演式加班。
    老板和 Leader 都是究极的结果导向——活干完、干漂亮,没人管你几点走。我个人体感是一周也就 1-2 天有加班,平时基本吃完晚饭就闪人。脑子木了下楼抽烟散步、摸鱼透气,没人死盯着考勤。

  2. 开发体验(对工程师的尊重)
    硬件/工具:标配 MacBook Pro ,Cursor 会员这种基础的都有。

信任度:之前我有个需求想做得更完善申请延期,Leader 原话是:“我们相信你是个优秀的工程师,你觉得需要额外时间把项目做精,我们支持。” 这种被信任的感觉,在大厂待过的兄弟应该懂多难得。

  1. 业务与团队
    硬实力:业务非常稳,现金流健康。看家产品如 Vita Mahjong 、Zen Word 长期霸榜海外。

氛围:没什么办公室政治,沟通成本低,很多同事都是互相内推回来的“背靠背”队友。决策靠数据驱动,不靠拍脑袋。

  1. 缺点直说
    公司是从小规模跑出来的,文档和流程肯定没大厂那么标准化。这对 Landing 能力有要求,更适合有经验的熟手,或者自驱力极强的职场新人。

  2. 职位与内推
    地点: 北京、成都、杭州(研发、测试、产品、美术、运营全线缺人)
    内推码:D138D2G
    投递链接: https://learnings.jobs.feishu.cn/s/E9GGA5-qr2Q

哥们亲自盯进度。有关于技术栈或团队的问题,评论区见。

在传统的软件开发模式中,我们的潜意识里会这样认为:一个业务对象,就必然对应数据库里的一张物理表。

比如我们要开发一个问卷系统,很自然地会建立 Survey(问卷表)、Question(题目表)、Response(答卷表)。表里定义好具体的列:titleVARCHARscoreIntcreatedAtDateTime。各司其职,结构清晰。当平台只有几十、上百个客户,且他们的业务流程基本一致时,这套做法不仅高效,而且非常优雅。

但是,现代企业级 SaaS(比如低代码平台、极其灵活的 CRM 系统)面临的核心挑战是:极端的个性化诉求规模化。

假如遇到这样的场景,你的平台服务了很多个企业客户(租户)。
A 企业希望在问卷里加一个"所属行业"字段;
B 企业希望加一个"紧急程度"字段;
C 企业甚至想完全新建一个叫"问卷回访跟进"的全新业务模块。
如果坚持"一对象一表"的传统架构,我们很快会遇到下面的问题:

  1. 触发 DDL 风暴 (Data Definition Language Storm):当上百个租户各自在界面上点击"添加字段"时,后台就要向数据库发送几十万条 ALTER TABLE ADD COLUMN 语句。DDL 操作通常会锁表(Metadata Lock),这在处于高并发读写状态的生产型数据库中,无异于自杀。
  2. 运维与管理的无底洞:如果为每个租户单独建表,1 万租户 × 50 张表 = 50 万张表。数据库的数据字典(系统表)会因为海量的元数据而极度膨胀。让备份、升级、统一修改字段都变得很困难。
  3. 隔离性极其脆弱:多租户环境下,由于大家的 Schema 完全长得不一样了,一套统一的代码体系很难去处理所有边缘情况,最后往往陷入"代码里写满 if-else 处理不同租户特殊逻辑"的泥潭。

面对这些困难,业界诞生了一个这样的架构选择:彻底放弃让应用层直接操作数据库结构。

数据库在低代码平台眼中,退化成了一个纯粹的、钝感的数据仓库。
不关心、也不知道具体的业务模型长什么样。
至于"系统里有哪些表、表里有哪些字段"这种原本属于 DBMS 级别的工作,被"上架"到了应用层来管理。

这就是元数据驱动架构(Metadata-driven Architecture)的起点。

用元数据描述结构:通用数据字典 (UDD)

为了在应用层"维护"一套数据库系统的逻辑,我们需要引入一个至关重要的概念:元数据 (Metadata)

如果说普通的业务数据记录的是"张三考了 95 分",那么元数据记录的就是"系统里有一个叫『问卷』的表,并且它有一列叫『分数』"。简单来说,元数据就是"描述数据的数据"

管理这些元数据的数据,我们称之为 通用数据字典 (Universal Data Dictionary, UDD)

它的核心思想是:既然底层数据库不让我们自由建表了,那我们就拿两张普通的表当"户口本",把用户想要的表结构"登记"在册。

具体来说,系统里只需要永远固定存在这两张表:

1. Objects 表(登记"有什么表")

当你在低代码后台点击"新建表单"并命名为"问卷调查"时,底层并没有执行神圣的 CREATE TABLE
系统只是往 Objects 这张表里,像普通记账一样插入了一行:
"嘿,客户 A 新建了一个叫 Survey(问卷)的虚拟表,ID 给它算作 1001 吧。"

2. Fields 表(登记"表里有什么列")

知道了有问卷表,还得知道问卷里有什么字段。Fields 表就是用来记这个的。

每当你在页面上拖拽生成一个"问卷标题"的输入框,系统就往 Fields 表里加上一行:
"客户 A 的 Survey 表里,多了一个叫 Title(标题)的文本字段。并且我规定,填写在这里的内容,未来统一存放到第 0 号储物格(SlotIndex: 0)里。"

理解关键点:在这个体系里,修改系统结构不再是高危的数据库操作(DDL),而变成了最简单的增删改查(CRUD)。表结构,本身也化作了普通的数据。

数据存储: 堆表与弹性列机制

上一节,我么把数据结构建好了。下一个问题是:真正的业务数据,到底存在哪里?

既然应用层不能动态建表,那唯一的解法就是:提前建好一张超级巨大的"万能表",把所有客户、所有表单的数据,全部大杂烩一样强行塞进去。

这张底层物理表,我们管它叫 堆表 (Heap Table)
你可以把它想象成一张行和列都无限向外延展的超级 Excel 表格。

它的结构极其无脑暴力,大致长这个样子:

唯一ID租户是谁这是什么表储物格\_0 (val_0)储物格\_1 (val_1)储物格\_2 (val_2)...
1客户A问卷表用户满意度调查5分进行中...
2客户A订单表iPhone 15 Pro8999元顺丰发货...
3客户B请假表病假老婆不舒服1天...

请仔细观察这张表的最右侧,跟着密密麻麻的 val_0, val_1val_500
这些列被称为 弹性列 (Flex Columns),而且它们全都是兼容性最强的文本类型 (VARCHAR)

堆表本身是一只没有任何感情的吞金兽,它完全不关心自己存的是问卷的名字、手机的价格,还是请假的天数。那到底谁知道 val_1 存的是什么鬼东西?

答案是:上一节讲到的 Fields 字典! 这两者的配合机制(Slot 映射)如下:

  1. 前端发请求:"把客户 A 的 iPhone 订单价格拿给我看看"。
  2. 翻译官(字典表)在脑子里翻译:"iPhone 订单价格... 对客户 A 来说,这玩意儿被登记在 val_1 这个储物格里!"
  3. 翻箱倒柜(抛向数据库):直接用原生 SQL 执行 SELECT val_1 FROM 堆表 WHERE ID = 2

就是这么简单。对底层的关系型数据库来说,这里完全不存在运行时的动态改表,也就是查一个固定列而已。
堆表负责死心塌地屯放数据,字典表作为"翻译密码本"负责解释这行数据到底是什么意思。 两套系统严丝合缝地咬合,完成了极其精彩的欺骗。

全用 VARCHAR 的代价与规范化格式

这种设计带来新的问题:

所有弹性列都是 VARCHAR 字符串,那我们怎么做大于、小于的范围比较?数字 95 和 100 怎么排序?日期 2024-01-01 和 2024-02-01 怎么查区间?

按照常规的字符串字典序逻辑,字符串 "100" 是排在 "95" 前面的(因为首字符 1 小于 9)。如果我们把 Score=100Score=95 原封不动作为字符串存进去,那么 ORDER BY Score DESC 的结果将是彻头彻尾的灾难。

这是所有的元数据架构必须跨过的一道硬核工程门槛。既然底层的原生数值类型和日期类型被我们人为抹杀掉了,我们就必须在应用层用一套严密的逻辑把规则补回来。这套机制被称为 规范化格式 (Canonical Format)

它的核心思想是:在把强类型的业务数据实际写入 val_N 弹性列之前,必须先经过一道编码层,将其强制转换为能够直接用于数据库比较运算符(><BETWEENORDER BY)的、符合标准字典序的字符串。

以下是一些关键的规范化规则:

逻辑类型原始输入值规范化后的字符串表示工程原理与优势
Number95"00000095.000"预先定义好总位数和小数位。左边补零对齐,保证字符串字典序等同于数值大小序。
Number-3"-0000003.000"处理负数时逻辑更复杂(需翻转补码),此处为简化展示,核心目的是解决负数排序。
Date2024-01-15"2024-01-15T00:00:00Z"严格采用 ISO 8601 格式,高位是年,低位是秒。时间维度的顺推恰好也是字典序的顺推。
Booleantrue"1"布尔值直接降维为单字符的 "1""0"

这套设计的本质是一笔架构层面的交易:我们刻意牺牲了底层数据存储的可读性,并付出了序列化/反序列化的计算开销,以此换取了整个平台架构在极大规模下的极致弹性。

在庞大的全是大文本的宽表上做 SQL 索引,其扫描效率和命中率在面临千万级数据时会直线下降。这个被称为"元数据性能税"的问题,是所有成熟架构后续必须攻克的下一个高峰,我们将在后续文章(透视表与查询优化)中集中讨论如何偿还这笔债。


一条数据的完整端到端旅程

我们把上面所有概念串在一起,看看在真实的系统中,一次普通的数据保存到底经历了怎样的一生。

应用场景:某个平台管理员在 Web 前端的问卷管理界面中,提交了一份新问卷的基础信息:{Title: "用户满意度调查", Status: "进行中"}

Step 1 · 流量入口与鉴权 (API Layer)

前端发起了 HTTP 请求。网关拦截后解析出这是 ORG-001 租户的流量,明确目标是要操作 Survey 这个模型。

POST /api/data/Survey
{ "Title": "用户满意度调查", "Status": "进行中" }

Step 2 · 唤醒元数据字典 (Metadata Lookup)

引擎的核心拦截器登场。它拿着 "Survey" 这个关键次去查询(通常是内存缓存里的)Objects 表,得到了这个虚拟模型的内部 ID 为 1001
接着查询 Fields 表,拉取到了这个模型下的所有字段配置及最重要的物理槽位:

逻辑字段名逻辑类型物理层 SlotIndex是否必填
TitleText0Yes
StatusText1No

Step 3 · 运行期强制校验与规范化编码 (Validation & Encoding)

引擎把请求中的 JSON 体拉过来进行对比:

  • "用户满意度调查" → 对应 Title 字段。系统检查其长度、是否符合纯文本规范。因为是 Text 类型,直接保持原样保留为待插入字符串。
  • "进行中" → 对应 Status 字段。校验通过,保持原样。
    (如果包含数字,就会在此处被格式化为前补零字符串)

Step 4 · 虚实转换:拼接最终物理 SQL (SQL Generation)

引擎拿着内存里已经编码好的干净数据,根据字典提供的映射关系,开始拼接能够在底层 PostgreSQL/MySQL 里直接运行的 SQL 文本。注意这里的列名已经被替换成了真正的物理列名 val_0, val_1

INSERT INTO physical_data
  (org_id, obj_id, val_0, val_1, created_at)
VALUES
  ('ORG-001', 1001, '用户满意度调查', '进行中', '2026-03-01T12:00:00Z');

Step 5 · 落盘与响应 (Persistence)

关系型数据库默默地执行了这条标准的 DML 语句,将数据持久化到堆表,并返回写入成功。引擎再将结果封装成 JSON 返回给前端。

回顾这一切:整个请求过程中,没有触发过任何一次 DDL 锁。被外界视作核心支柱的 Survey 这张业务表,自始至终在物理层面都不存在过 —— 它只是配置系统里静静躺着的一行设置。而在平台的用户端视角看来,他们的录入、查询操作,却与使用专属 MySQL 实例并无二致。


小结

元数据驱动的核心并不是消灭了结构,而是做了一次巧妙的维度提升。

我们将传统数据库赖以生存的 Schema 骨架从底层剥离,强行搬到了更高一层的“应用层数据字典”中。这层额外的中间层间接性,赋予了平台很强的生命力和扩展弹性。无论租户是一千、一万还是十万,无论他们想要定义怎样千奇百怪的表单和数据模型,底层物理依然是一张纹丝不动、便于统一治理和灾备的超级宽表。

只要你的系统存在“极端允许用户在运行时定义数据结构”的需求,这套宽表+字典模型几乎是目前工业界唯一可行的顶层解法。

我长期存在比较强的焦虑/低自尊/内耗/抑郁情绪, 曾经以为可以独自解决.但最近看来应该算"阳光型抑郁症"了.

我不确定有没有自己是否真的有抑郁症,只想找个医院检查下,如果能确诊抑郁症, 我感觉我的内心反而会舒服一些.

只想询问一下大致流程和等待时间需要多久, 目前看挂号得提前一周预约,多次去才能确诊的话周期会拉到多长?一个月?两个月?花费呢?

另外就是我应该挂哪个科?精神科/心理科/心身科 这些科室有什么区别? 我看很多医院的名称不同,是否职能也不同?