systemd 的前世后生

从 init 系统说起
Linux 操作系统的启动首先从 BIOS 开始,接下来进入 boot loader,由 bootloader 载入内核,进行内核初始化。内核初始化的最后一步就是启动 PID 为 1 的 init 进程。这个进程是系统的第一个进程。它负责产生其他所有的用户进程。init 进程以守护进程(也就是服务)的方式存在,是所有其他进程的祖先。init 进程非常独特,能够完成其他进程无法完成的任务。
init 系统能够定义、管理和控制 init 进程的行为。它负责组织和运行许多独立的或相关的初始化工作(因此被称为 init 系统),从而让计算机系统进入某种用户预定义的运行模式,比如命令行模式或图形界面模式 。
对于一个操作系统而言,仅仅将内核运行起来是毫无实际用途的,必须由 init 系统将操作系统初始化为可操作的状态。比如启动 shell 后,便有了人机交互,这样就可以让计算机执行一些程序完成有实际意义的任务。或者启动 X 图形系统以便提供更佳的人机界面,更加高效的完成任务。这里,字符界面的 shell 或者 X 系统都是一种预设的运行模式。

随着计算机系统软硬件的发展,init 系统也在不断的发展变化之中。大体上的演进路线为 sysvinit -> upstart -> systemd。虽然本文的目的是要介绍 systemd,但是笔者觉得如果能从历史发展的角度观察 init 系统的演进,将会帮助我们更好的理解、使用 systemd。

sysvinit
sysvinit 就是 System V 风格的 init 系统,顾名思义,它源于 System V 系列的 UNIX。最初的 linux 发行版几乎都是采用 sysvinit 作为 init 系统。sysvinit 用术语 runlevel 来定义 “预订的运行模式”。比如 runlevel 3 是命令行模式,runlevel 5 是图形界面模式,runlevel 0 是关机,runlevel 6 是重启。sysvinit 会按照下面的顺序按部就班的初始化系统:

激活 udev 和 selinux
设置定义在 /etc/sysctl.conf 中的内核参数
设置系统时钟
加载 keymaps
启用交换分区
设置主机名(hostname)
根分区检查和 remount
激活 RAID 和 LVM 设备
开启磁盘配额
检查并挂载所有文件系统
清除过期的 locks 和 PID 文件
最后找到指定 runlevel 下的脚本并执行,其实就是启动服务。
除了负责初始化系统,sysvinit 还要负责关闭系统,主要是在系统关闭是为了保证数据的一致性,需要小心地按照顺序进行任务的结束和清理工作。另外,sysvinit 还提供了很多管理和控制系统的命令,比如 halt、init、mesg、shutdown、reboot 等等。
sysvinit 的优点是概念简单。特别是服务(service)的配置,只需要把启动/停止服务的脚本链接接到合适的目录就可以了。
sysvinit 的另一个重要优点是确定的执行顺序,脚本严格按照顺序执行(sysvinit 靠脚本来初始化系统),一个执行完毕再执行下一个,这非常有益于错误排查。

同时,完全顺序执行任务也是 sysvinit 最致命的缺陷。如果 linux 系统只用于服务器系统,那么漫长的启动过程可能并不是什么问题,毕竟我们是不会经常重启服务器的。但是现在 linux 被越来越多的用在了桌面系统中,漫长的启动过程对桌面用户来说是不能接受的。除了启动慢,sysvinit 还有一些其它的缺陷,比如不能很好的处理即插即用的设备,对网络共享磁盘的挂载也存在一定的问题,于是 init 系统开始了它的进化之旅。

upstart
由于 sysvinit 系统的种种弊端,Ubuntu 的开发人员决定重新设计和开发一个全新的 init 系统,即 upstart 。upstart 是第一个被广泛应用的新一代 init 系统。

upstart 基于事件机制,比如 U 盘插入 USB 接口后,udev 得到内核通知,发现该设备,这就是一个新的事件。upstart 在感知到该事件之后触发相应的等待任务,比如处理 /etc/fstab 中存在的挂载点。采用这种事件驱动的模式,upstart 完美地解决了即插即用设备带来的新问题。采用事件驱动机制也带来了一些其它有益的变化,比如加快了系统启动时间。sysvinit 运行时是同步阻塞的。一个脚本运行的时候,后续脚本必须等待。这意味着所有的初始化步骤都是串行执行的,而实际上很多服务彼此并不相关,完全可以并行启动,从而减小系统的启动时间。

upstart 的特点
upstart 解决了之前提到的 sysvinit 的缺点。采用事件驱动模型的 upstart 可以:

更快地启动系统
当新硬件被发现时动态启动服务
硬件被拔除时动态停止服务
这些特点使得 upstart 可以很好地应用在桌面或者便携式系统中,处理这些系统中的动态硬件插拔特性。

主角 systemd 登场
systemd 是 linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度。systemd 和 ubuntu 的 upstart 是竞争对手,但是时至今日 ubuntu 也采用了 systemd,所以 systemd 在竞争中胜出,大有一统天下的趋势。其实,systemd 的很多概念都来源于苹果 Mac OS 操作系统上的 launchd。
systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂,下图展示了 systemd 的架构(此图来自互联网):
systemd 能够在与 upstart 的竞争中胜出自然有很多过人之处,接下来让我们介绍一些 systemd 的主要优点。
兼容性
systemd 提供了和 sysvinit 兼容的特性。系统中已经存在的服务和进程无需修改。这降低了系统向 systemd 迁移的成本,使得 systemd 替换现有初始化系统成为可能。
启动速度
systemd 提供了比 upstart 更激进的并行启动能力,采用了 socket / D-Bus activation 等技术启动服务。一个显而易见的结果就是:更快的启动速度。为了减少系统启动时间,systemd 的目标是:

尽可能启动更少的进程
尽可能将更多进程并行启动
同样地,upstart 也试图实现这两个目标。下图展示了 upstart 相对于 sysvinit 在并发启动这个方面的改进。
upstart 增加了系统启动的并行性,从而提高了系统启动速度。但是在 upstart 中,有依赖关系的服务还是必须先后启动。比如任务 A,B,(C,D)因为存在依赖关系,所以在这个局部,还是串行执行。

systemd 能够更进一步提高并发性,即便对于那些 upstart 认为存在相互依赖而必须串行的服务,比如 Avahi 和 D-Bus 也可以并发启动。从而实现如下图所示的并发启动过程(此图来自互联网):
在 systemd 中,所有的任务都同时并发执行,总的启动时间被进一步降低为 T1。可见 systemd 比 upstart 更进一步提高了并行启动能力,极大地加速了系统启动时间。

systemd 提供按需启动能力

当 sysvinit 系统初始化的时候,它会将所有可能用到的后台服务进程全部启动运行。并且系统必须等待所有的服务都启动就绪之后,才允许用户登录。这种做法有两个缺点:首先是启动时间过长,其次是系统资源浪费。

某些服务很可能在很长一段时间内,甚至整个服务器运行期间都没有被使用过。比如 CUPS,打印服务在多数服务器上很少被真正使用到。您可能没有想到,在很多服务器上 SSHD 也是很少被真正访问到的。花费在启动这些服务上的时间是不必要的;同样,花费在这些服务上的系统资源也是一种浪费。

systemd 可以提供按需启动的能力,只有在某个服务被真正请求的时候才启动它。当该服务结束,systemd 可以关闭它,等待下次需要时再次启动它。
这有点类似于以前系统中的 inetd,并且有很多文章介绍如何把过去 inetd 管理的服务迁移到 systemd。

采用 linux 的 cgroups 跟踪和管理进程的生命周期

systemd 利用了 Linux 内核的特性即 cgroups 来完成跟踪的任务。当停止服务时,通过查询 cgroups ,systemd 可以确保找到所有的相关进程,从而干净地停止服务。
cgroups 已经出现了很久,它主要用来实现系统资源配额管理。cgroups 提供了类似文件系统的接口,使用方便。当进程创建子进程时,子进程会继承父进程的 cgroups 。因此无论服务如何启动新的子进程,所有的这些相关进程都会属于同一个 cgroups ,systemd 只需要简单地遍历指定的 cgroups 即可正确地找到所有的相关进程,将它们一一停止即可。

启动挂载点和自动挂载的管理

传统的 linux 系统中,用户可以用 /etc/fstab 文件来维护固定的文件系统挂载点。这些挂载点在系统启动过程中被自动挂载,一旦启动过程结束,这些挂载点就会确保存在。这些挂载点都是对系统运行至关重要的文件系统,比如 HOME 目录。和 sysvinit 一样,Systemd 管理这些挂载点,以便能够在系统启动时自动挂载它们。systemd 还兼容 /etc/fstab 文件,您可以继续使用该文件管理挂载点。

有时候用户还需要动态挂载点,比如打算访问 DVD 或者 NFS 共享的内容时,才临时执行挂载以便访问其中的内容,而不访问光盘时该挂载点被取消(umount),以便节约资源。传统地,人们依赖 autofs 服务来实现这种功能。
systemd 内建了自动挂载服务,无需另外安装 autofs 服务,可以直接使用 systemd 提供的自动挂载管理能力来实现 autofs 的功能。

实现事务性依赖关系管理

系统启动过程是由很多的独立工作共同组成的,这些工作之间可能存在依赖关系,比如挂载一个 NFS 文件系统必须依赖网络能够正常工作。systemd 虽然能够最大限度地并发执行很多有依赖关系的工作,但是类似”挂载 NFS”和”启动网络”这样的工作还是存在天生的先后依赖关系,无法并发执行。对于这些任务,systemd 维护一个”事务一致性”的概念,保证所有相关的服务都可以正常启动而不会出现互相依赖,以至于死锁的情况。

日志服务

systemd 自带日志服务 journald,该日志服务的设计初衷是克服现有的 syslog 服务的缺点。比如:

syslog 不安全,消息的内容无法验证。每一个本地进程都可以声称自己是 Apache PID 4711,而 syslog 也就相信并保存到磁盘上。
数据没有严格的格式,非常随意。自动化的日志分析器需要分析人类语言字符串来识别消息。一方面此类分析困难低效;此外日志格式的变化会导致分析代码需要更新甚至重写。
systemd journal 用二进制格式保存所有日志信息,用户使用 journalctl 命令来查看日志信息。无需自己编写复杂脆弱的字符串分析处理程序。

systemd journal 的优点如下:
简单性:代码少,依赖少,抽象开销最小。
零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
移植性:日志文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
性能:添加和浏览日志非常快。
最小资源占用:日志数据文件需要较小。
统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
安全性:日志文件是可以验证的,让无法检测的修改不再可能。

在了解了 systemd 的种种优势之后让我们开始认识它的一些基本概念。

unit(单元)
系统初始化需要做的事情非常多。需要启动后台服务,比如启动 ssh 服务;需要做配置工作,比如挂载文件系统。这个过程中的每一步都被 systemd 抽象为一个配置单元,即 unit。可以认为一个服务是一个配置单元,一个挂载点是一个配置单元,一个交换分区的配置是一个配置单元等等。systemd 将配置单元归纳为以下一些不同的类型。然而,systemd 正在快速发展,新功能不断增加。所以配置单元类型可能在不久的将来继续增加。下面是一些常见的 unit 类型:

service :代表一个后台服务进程,比如 MySQLd。这是最常用的一类。
socket :此类配置单元封装系统和互联网中的一个套接字 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。每一个套接字配置单元都有一个相应的服务配置单元 。相应的服务在第一个”连接”进入套接字时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。
device :此类配置单元封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备配置单元出现。
mount :此类配置单元封装文件系统结构层次中的一个挂载点。Systemd 将对这个挂载点进行监控和管理。比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。Systemd 会将 /etc/fstab 中的条目都转换为挂载点,并在开机时处理。
automount :此类配置单元封装系统结构层次中的一个自挂载点。每一个自挂载配置单元对应一个挂载配置单元 ,当该自动挂载点被访问时,systemd 执行挂载点中定义的挂载行为。
swap:和挂载配置单元类似,交换配置单元用来管理交换分区。用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。
target :此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。这样便可以对配置单元做一个统一的控制。这样就可以实现大家都已经非常熟悉的运行级别概念。比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。 (例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别 5)
timer:定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了 atd、crond 等传统的定时服务。
snapshot :与 target 配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
path:文件系统中的一个文件或目录。
scope:用于 cgroups,表示从 systemd 外部创建的进程。
slice:用于 cgroups,表示一组按层级排列的单位。slice 并不包含进程,但会组建一个层级,并将 scope 和 service 都放置其中。

每个配置单元都有一个对应的配置文件,系统管理员的任务就是编写和维护这些不同的配置文件,比如一个 MySQL 服务对应一个 mysql.service 文件。这种配置文件的语法非常简单,用户不需要再编写和维护复杂的系统脚本了。

依赖关系
虽然 systemd 将大量的启动工作解除了依赖,使得它们可以并发启动。但还是存在有些任务,它们之间存在天生的依赖,不能用”套接字激活”(socket activation)、D-Bus activation 和 autofs 三大方法来解除依赖。比如:挂载必须等待挂载点在文件系统中被创建;挂载也必须等待相应的物理设备就绪。为了解决这类依赖问题,systemd 的配置单元之间可以彼此定义依赖关系。Systemd 用配置单元定义文件中的关键字来描述配置单元之间的依赖关系。比如:unit A 依赖 unit B,可以在 unit B 的定义中用”require A”来表示。这样 systemd 就会保证先启动 A 再启动 B。

systemd 事务
systemd 能保证事务完整性。Systemd 的事务概念和数据库中的有所不同,主要是为了保证多个依赖的配置单元之间没有环形引用。比如存在 unit A、B、C,假如它们的依赖关系如下(此图来自互联网):

存在循环依赖,那么 systemd 将无法启动任意一个服务。此时 systemd 将会尝试解决这个问题,因为配置单元之间的依赖关系有两种:required 是强依赖;want 则是弱依赖,systemd 将去掉 wants 关键字指定的依赖看看是否能打破循环。如果无法修复,systemd 会报错。systemd 能够自动检测和修复这类配置错误,从而极大地减轻了管理员的排错负担。

target 和运行级别
systemd 用目标(target)替代了运行级别的概念,提供了更大的灵活性,如您可以继承一个已有的目标,并添加其它服务,来创建自己的目标。下表列举了 systemd 中的 target 和 sysvinit 中常见的 runlevel 的对应关系:

sysvinit runlevel systemd target 描述
0 poweroff.target 关闭系统。
1,s,single rescue.target 单用户模式。
2,4 multi-user.target 用户定义/域特定运行级别。默认等同于 3。
3 multi-user.target 多用户,非图形化。用户可以通过多个控制台或网络登录。
5 graphical.target 多用户,图形化。通常为所有运行级别 3 的服务外加图形化登录。
6 reboot.target 重启。
emergency emergency.target 紧急 Shell。
总结
本文简要的介绍了 init 系统的发展历史,并概要的介绍了 systemd 的基本概念。由于相比其它的 init 系统优势巨大,所以 systemd 已经被各大 linux 版本接受,在 linux init 系统中一统天下。

ubuntu20.04 启用rc.local

ubuntu20.04 不再使用initd管理系统,改用systemd.

使用systemd设置开机启动
为了像以前一样,在/etc/rc.local中设置开机启动程序,需要以下几步:

1、实现原理
systemd 默认会读取 /etc/systemd/system 下的配置文件,该目录下的文件会链接 /lib/systemd/system/ 下的文件。一般系统安装完 /lib/systemd/system/ 下会有 rc-local.service 文件,即我们需要的配置文件。
target 用于指定 什么时候启动 我们自己自定的软件。
1)将 /lib/systemd/system/rc-local.service 链接到 /etc/systemd/system/ 目录下面来:
ln -fs /lib/systemd/system/rc-local.service /etc/systemd/system/rc-local.service

说明:
[Unit] 区块:启动顺序与依赖关系。
ConditionFileIsExecutable=/etc/rc.local
After=network.target
ConditionFileIsExecutable指定了执行的文件,

After 表示在 network.target 这个target后面进行执行。也就是网络启动完成之后,执行 /etc/rc.local 文件。

[Service] 区块:启动行为,如何启动,启动类型。
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
RemainAfterExit=yes
GuessMainPID=no

3) [Install] 区块,定义如何安装这个配置文件,即怎样做到开机启动。
[Install]
WantedBy=multi-user.target
Alias=rc-local.service

[Install] 块是我们自己编辑新增的

2、创建/etc/rc.local文件
touch /etc/rc.local
3、赋可执行权限
chmod 755 /etc/rc.local
4、编辑rc.local
添加需要开机启动的任务  
#!/bin/bash
echo “test rc ” > /var/test.log
# startup redis-server:
/usr/local/bin/redis-server /usr/redis/redis.conf
5、执行reboot重启系统
查看test.log  
6、总结
通过 /etc/systemd/system/rc-local.service 文件来达到启动时执行 /etc/rc.local 文件的目的。

github免用户名密码管理代码

github免用户名密码管理代码

一、问题描述

git管理代码需要输入用户名密码,为避免重复操作,可设置保存用户名和密码。第一次输入后数据保存,后续管理代码不需再次输入。

用户名和密码明文保存会有安全隐患,对安全要求高的不建议采用。

二、操作步骤

1、git安装完成后,打开git bash,配置git全局保存用户名密码,输入如下命令:git config –global credential.helper store

git config –global credential.helper store

该步骤会在windows用户主目录:C:\Users\用户名下生成一个.gitconfig文件,内容为:

[credential]
helper = store

2、然后在git bash上clone或者pull代码,要求输入用户名密码。输入完成,会在windows用户主目录:C:\Users\用户名下生成一个.git-credentials文件,内容为保存的用户名和密码,明文保存有安全隐患。

3、后续clone、pull或者push等操作都不需要再输入用户名密码。

不能出众,那就出局—从一个人到900人的超长马拉松,Odoo CEO的实战心路

星光不问赶路人,时光不负有心人

Odoo科普:自2004年成立以来,Odoo一直采用开源商业模式为核心运营,除了在企业版提供的30个核心应用程序之外,Odoo在全球拥有2万名活跃成员的社区, 提供了超过1.7万个应用程序,满足了广泛的业务需求,已经成为最大商业应用库。

公司规模从2004年的一个人,到2020年九百人的持久马拉松,一路荆棘,一路成长,这一份企业领军人物对于危机管理的实战心路,相信你会有所启发!Odoo作为中小企业信息化的开源解决方案提供者,希望能为中小企业提供借鉴,在危机中找到活下去的突破口。下文将以Fabien Pinckaers第一人称进行讲述。

不论是08年金融危机,还是2020年的疫情打击,我有一个深刻的感受:企业面对的最大威胁往往不是来自于外部,而来自于内部的商业模式的探索和业务持续优化。基于此,提供以下几点企业经营管理的建议和思考,聊以与各位共度艰难时期。

1.聚焦长期效益。

当情况变量变得混乱的时候,这个时候营收下降是正常的,需要把公司有限的精力转移到具有长期效益的重点领域,比如实施团队的项目实施技巧培训,公司内部更好的运营架构,产品调研上新和开发等。放眼长期效益,而不是在项目获客上纠结停留。

2.危中有机,把握背后的机遇,落子无悔

疫情当下,全球范围内启动在家办公,我们也梳理过,odoo的历史机会是什么?答案是请人请人再请人,企业的根基是人才,在特殊的慢下来的时期,集中子弹广纳贤才。两年之前,招聘方面我们经历过阵痛,很难请到合资格的R&D程序员岗位。危机期间,我们加码了程序员的招聘投入,推出了价值10w的程序员入职奖金(写完这篇,小编就要去学python了…酸了酸了),旨在吸引高标准的人才加入odoo, 实现公司规模扩大,满足市场产品迭代的需求,到明年,Odoo员工会达到1400人。

同时,建议大家不妨关注一下市场推广的机会。这个时候可以提高市场推广的预算,大的推广投资项目可以在这个时候下手。绝大多数人恰恰不会考虑市场推广,如果有好的方案和机会,不妨评估抄底,做好准备。

3.快没子弹的时候怎么办?

关于优先级
专注在核心任务上面,比如可以减少见客户。

关于裁员
到了不得不考虑裁员的地步,我建议频率要低,但是最好一次性裁到位。通知之前,要开诚布公地和员工沟通公司的处境和计划,避免糊弄员工。如果情况到了很糟糕的时候,作为管理者肯定是写在脸上的难看,员工是可以感受到的,透明化去沟通,低频裁员不会动摇军心,以维护多年来建立的信任。

关于减速
营收减速,新单和客户可以减少,长期受益的价值体系,绝对不可以忽视。每次危机,我们都会加大研发投入,短期很难见效,但正是长期坚持产品的打磨迭代,造就了今天Odoo的地位——世界最大的开源管理软件库。我们成长曲线也是波动的,高光时刻和低谷并存,过去13年来,每年的平均增长达到了71.47%。一定要把工作重心放在长期价值的建立上,提供的商业价值会不断强化公司的竞争力,成为强大的内生动力,推动企业步步为营,突出重围。企业经营是一场持久马拉松,眼光和战略足够长远,才能行稳致远。

4.活下去

每个高速成长的公司都经历过一地鸡毛的困难时期,在这一点上,没有例外。从现金流预警到破产,你有两年的时间。供应商的付款死线、员工薪酬都促使企业去找到增收的渠道,Odoo每次绝境都幸运地解决了问题,救公司于水火,回到正确的轨道上来。我解决问题的关键是从根本上解决问题,找到深层次问题所在,让业务进阶,撬动更多的打法和资源。所以企业主必须要深入了解业务和市场,找到疑难杂症的源头,对症下药。

每一次困难期的考验都会指引你走向成功。
成功和失败的公司区别在于,前者可以在情况变坏之前,活下来。

5.CEO之于企业

从模型可以看到,公司处于起步小规模的时候,CEO的角色是从上而下的,管理决策、为公司提供更多的指导、强化组织能力和公司文化的建立。公司规模扩大的时候,需要向自下而上的模式转换,下放更多的权利给员工,自下而上的创新和机制的建立,基层员工提供更多的内容。然而危机中,需要回到自上而下的角色模式,个体的创造力需要放到最低,需要强有力的领导力,集中力量攻坚。在此期间,专注是非常重要的,重要的话,要强调三次,敲黑板!

很多时候,优先级和业务重点经营者一定要有清楚的定位,必须清楚地知道你的产品方向在哪里,集中强将专攻少数项目。这个时候,放弃社交,放弃客户,放弃展会,集中在对公司业务优化和提高上,我很少参加商业展会,这是我一贯的原则。

在投资领域,有一个默契的原则,如果你在各种社交场合经常见到一个公司的创始人,那么这个公司不值得投。时间碎片化在无效的领域,这样的创始人,很难为公司带来核心价值,因为他本身不具价值。公司自然不会做出靓眼的成就,投资的真金白银,很有可能付之东流。

6.市场化产品

关于定价
定价是一个技术活,远比你想象的要复杂的多。产品价位的影响远超想象,一般而言,提价20%,你可能利润会增加40%-60%。在这方面,我是踩过坑的,公司规模很小的时候,总是倾向于低估自己服务的价值,日开发服务费设定为200欧,接下来的几年没日没夜地挣扎在为人民服务的苦线上。(此处CEO的苦笑省略一万字…)

关于商业模式
商业模式可以说是最关键的。我花了十年的时间,探索到正确的商业模式。我们有标准化的企业版和社区版,公司变得可以盈利,能够增加两倍的研发投入,进而持续地提供odoo的商业价值。我们和全球2576个优秀的伙伴合作,伙伴为客户提供技术维护服务。这是一个可持续的商业模式,客户在升级系统或遇到问题的时候,都可以得到迅速的反馈。对于任何规模的服务型的公司都是一样, 在销售或者运营服务方面做一些尝试和改变,实现规模升级。

关于差异化价值
不能出众 那就出局。商业模式的要义在于提供差异化价值,你要做的是提供不可替代的商业价值,而不是优化。Odoo能够迅速扩张的原因不是因为我们比Oracle或者SAP好,大厂比我们市场运营能力强大,在垂直领域和不同行业有很好的解决方案,然而我们品牌定位独到,性价比方面优胜,产品极致追求用户友好,具有很高的灵活性和定制化的可能性。像甲骨文这样的大厂,强大之处也正是弱点所在。Odoo差异性的价值定位,为我们开辟了一条独特的赛道。产品方面,在自己的优势领域,不断投入研发,同时加强对竞品的分析,确保开发的性能是更加优化的。头部巨头不断加强影响力的情况下,中小企业必须要致力跻身于少数的几个可以提供差异化价值的玩家,才能找到长久发展的原生引擎。