C2M的四大必要条件

曾鸣和宋斐在他们2012年的文章中曾经指出,生产组织要真正从厂商为中心转向以消费者为中心,是需要若干个条件的:

一是消费者需求的转变。传统的“小品种、大批量”的生产模式是与收入水平较低、以满足生活必须为目的的消费需求结合在一起的。由于消费者的必须消费大致上是类似的,对于个性的要求不是那么高,因而制造商进行竞争的关键就是要压成本、提效率,只要把最终的价格压下来,就能在市场上胜出。但是当消费者的收入进一步提升之后,他们的需求就会升级,从满足必须转向到对个性化的追求。在这个阶段,他们的需求就会多样化、长尾化,C2M等以消费者为中心的商业模式才会有真正的市场。

二是互联网技术的发展。即使消费者的需求发生了改变,开始对个性化有了诉求,如果不能及时捕捉这些需求,并将它们转给制造商,整个C2M的过程就无法完成。而要实现这一切,技术,尤其是互联网技术的发展显然是不可或缺的。

三是柔性化生产技术的普及。一旦制造商获取了消费者的需求,下面的任务就是要根据这些需求组织生产。但是,这一切的实现并不简单。如果消费者的需求过于多样化,商品品类过于繁多,制造商对于产品质量的把控就会变得十分困难。一旦在某个参数上出错,产品就可能难以满足消费者的需求。

四是社会化协作的实现。要实现商品从制造到销售的整个流程,单单依靠制造商显然是不行的,它还依靠采购、物流、分销等各个环节的支撑。一旦客户有了一个个性化的需求,制造商就要先根据需求实现采购,在进行生产后,还需要按照要求将产品交付物流,送到消费者手中。如果这些环节中的某一个不能实现,那么整个流程就可能无法运转。

Vagrant Config file

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
#disk = 'D:\\data\\temp\\secondDisk.vdi'
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "ubuntu/bionic64"
  config.disksize.size = "150GB"
  config.vm.synced_folder "D:\\projects", "/projects", type: "nfs"
  config.vm.network "private_network", ip: "192.168.56.20"
  
  config.vm.provider :virtualbox do |vb|
  #   # Don't boot with headless mode
  #   vb.gui = true
  #
  #   # Use VBoxManage to customize the VM. For example to change memory:
    vb.customize ["modifyvm", :id, "--memory", "4096", "--cpus", "2"]
  end

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
#	config.vm.provider "virtualbox" do |vb|
#		unless File.exist?(disk)
#			vb.customize ['createhd', '--filename', disk, '--variant', 'Fixed', '--size', 10 * 1024]
#		end
#		vb.memory = "1024"
#		vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', disk]
#	end
end





























ERROR: error while removing network 解决

ERROR: error while removing network: network cloudservices_default id 757495ac40c7aa62c6797f5fdb852bd80b91d0bb4ebb1bbc46

ded66be03cd3c6 has active endpoints

This is a stale endpoint case. Do you happen to have the error log when that container that was originally removed (which left the endpoint in this state).

BTW, if the container is removed, but the endpoint is still seen, then one can force disconnect the endpoint using docker network disconnect -f {network} {endpoint-name} . You can get the endpoint-name from the docker network inspect {network} command.

github里提问的回答原话

From <https://github.com/moby/moby/issues/17217>

网上的说法是此bug不常见,但是竟然被我碰到了,这个endpoint本来应该已经不存在了,但是不知道什么原因还存在着,二相关的容器已经被移除了。

这时需要用

docker network disconnect -f <container id>  <endpoint name>

来移除相关的endpoint。

Container id:报错是显示的一长串id就是了

Endpoint name: 就是用down命令shut不掉的那些容器的name

此命令需要执行多次,知道所有endpoint被移除为止。

然后只能用docker rm -f 命令来shut 容器, docker-compose down还是无法移除。

github oauth第三方登陆

官方文档地址

https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#web-application-flow

通过token能操作的api列表

Git token 联合登陆(SSO)又两种方式:

– Web-base application

– Nonweb-base application (这种方式是受限的)

Nonweb-base的限制:

  • 只支持https模式,不支持ssh模式

说明:

Once you have a token, you can enter it instead of your password when performing Git operations over HTTPS.

For example, on the command line you would enter the following:

$ git clone https://github.com/username/repo.git
Username: your_username
Password: your_token

Personal access tokens can only be used for HTTPS Git operations. If your repository uses an SSH remote URL, you will need to switch the remote from SSH to HTTPS.

If you are not prompted for your username and password, your credentials may be cached on your computer. You can update your credentials in the Keychain to replace your old password with the token.

应用: 官方文档

在python里遍历文件夹

Python 里遍历文件夹的一个简单的用法,在这里记录一下而已。

Method of iter folder in python codes, record here

import os
import re


for root, _dir, _fiels in os.walk('c:\\data\\handback\\data'):
    result = re.search(r'.*[/\\](\d*)[/\\](\w{2}-\w{2})', root)
    if result:
        number = result.group(1)
        language_name = result.group(2)
        print('workbench %s language %s files %s' % (workbench_id, language_name, _fiels,))

小辫儿调侃风波

今天在健身房锻(lang)炼(fei)身(shi)体(jian)的时候,跑步机前面的电视上正在播放某个视频平台制作的国风节目,老友们看的津津有味,我说了句“这年头也就他们还在坚持这些传统文化了。”然后我又多了一句嘴,“还有张云雷。”

朋友嗤笑,张云雷最近被骂死了好吗,乱调侃别人。

然后我就住嘴了,心里却止不住的想,张云雷调侃了我在看到骂他的文章后才知道名字的名人后,就被各种口诛笔伐,仿佛做了多大的恶一般,这一切的根源是什么呢?

想了很久,嗯,还是他太年轻,太幼稚了, 图样图森破啊。

我想不明白他当年在设计这个哏的时候是怎么想的呢?放着那么多名气满天飞的明星不去调侃,比如岳岳调侃蔡琴,调侃各路神仙妖魔,安全效果又好,可他小辫儿为什么偏偏调侃这两位呢?

我想问问我身边的人,在这些充满火药味的文章出来之前有几个人听说过他们,当时小辫儿在台上放出这个包袱的时候,台下有多少人是一脸懵逼的赶紧掏出手机来百度一下的。

小辫儿真的错了,要他道歉不委屈。

真的。

[转载]Kafka 入门介绍

Table of Contents

Kafka 的大名相信大家早有耳闻,就是《变形记》的作者……咳咳……是一个著名的分布式消息队列,据说是因为作者特别喜欢作家卡夫卡才取名 Kafka 的。开始接触 Kafka 时最头疼的就是它的概念,什么是 group,什么是 partition …… 这里咱们从头开始理一理 Kafka 的基本概念。

Topic

一个 Topic(主题)对应一个消息队列。Kafka 支持多生产者,多消费者,对应下图:

多个生产者将数据发送到 Kafka 中,Kafka 将它们顺序存储,消费者的行为留到下面讨论。我们知道 Kafka 的目标是大数据,如果将消息存在一个“中心”队列中,势必缺少可伸缩性。无论是生产者/消费者数目的增加,还是消息数量的增加,都可能耗尽机器的性能或存储。

因此,Kafka 在概念上将一个 Topic 分成了多个 Partition,写入 topic 的消息会被(平均)分配到其中一个 Partition。Partition 中会为消息保存一个 Partition 内唯一的 ID ,一般称为偏移量(offset)。这样当性能/存储不足时 Kafka 就可以通过增加 Partition 实现横向扩展。

现在我们有了一个队列的消息,那么如何发送给消费者呢?

消费模型

一般有两种消费模型,不同模型下消费者的行为是不同的:

  • 队列模式(也叫点对点模式)。多个消费者共同消费一个队列,每条消息只发送给一个消费者。
  • 发布/订阅模式。多个消费者订阅主题,每个消息会发布给所有的消费者。

两种方式各有优缺点:

  • 队列模式中多个消费者共同消费同一个队列,效率高。
  • 发布/订阅模式中,一个消息可以被多次消费,能支持冗余的消费(例如两个消费者共同消费一个消息,防止其中某个消费者挂了)

显然要构建一个大数据下的消息队列,两种模式都是必须的。因此 Kafka 引入了 Consumer Group(消费组)的概念,Consumer Group 是以发布/订阅模式工作的;一个 Consumer Group 中可以有多个 Consumer(消费者),Group 内的消费者以队列模式工作,如下图:

上面提到,Kafka 中的消息是以 Partition 存储的,那么它是如何与 Consumer 对接的呢?

Partition 与消费模型

上面提到,Kafka 中一个 topic 中的消息是被打散分配在多个 Partition(分区) 中存储的, Consumer Group 在消费时需要从不同的 Partition 获取消息,那最终如何重建出 Topic 中消息的顺序呢?

答案是:没有办法。Kafka 只会保证在 Partition 内消息是有序的,而不管全局的情况。

下一个问题是:Partition 中的消息可以被(不同的 Consumer Group)多次消费,那 Partition中被消费的消息是何时删除的? Partition 又是如何知道一个 Consumer Group 当前消费的位置呢?

  1. 无论消息是否被消费,除非消息到期 Partition 从不删除消息。例如设置保留时间为 2 天,则消息发布 2 天内任何 Group 都可以消费,2 天后,消息自动被删除。
  2. Partition 会为每个 Consumer Group 保存一个偏移量,记录 Group 消费到的位置。如下图:

上面我们提到的都是 Partition 与 Consumer Group 之间的关系,那 Group 中的 Consumer 又是如何与 Partition 对应的呢?一般来说这也是最不容易理解的部分。但其实机制很简单:

  • 同一个 Consumer Group 内,一个 Partition 只能被一个 Consumer 消费。
  • 推论1:如果 Consumer 的数量大于 Partition 数量,则会有 Consumer 是空闲的。
  • 推论2:如果 Consumer 的数量小于 Partition 数量,则一个 Consumer 可能消费多个 Partition。

左边的 Consumer Group 中的 C4 是空闲的,而右边 Group 中的 C1 则需要消费两个 Partition 。由于 C1 中消息可能来源于两个 Partition,此时如果需要确保消息的顺序,必须先判断消息的 Partition ID。

在分配 Partition 时,肯定是希望不同的 Consumer 的负载大致相同,具体的分配算法有 Range 的 RoundRobin 两种,文末会给出参考资料,这里不再赘述。

物理存储

上面提到的 Topic, Partition 都是抽象的概念。每个 Partition 最终都需要存储在物理机器上,在 Kafka 中一般把这样的物理机器称为 Broker,可以是一台物理机,也可以是一个集群。

在讲概念的时候我们没有考虑到物理机可能会损坏的问题,这会导致某个 Partition 失效,上面存储的消息丢失,那还说什么高可用?所以一般需要对数据做冗余 (replication)。换言之,需要存储多份 Partition 在不同的 Broker 上,并为它们的数据进行同步。那么从物理的视角:

上图中,某个 Topic 分成了 3 个 Partition,每个 Partition 保存了两个副本,副本平均分配到 3 个 Broker 上。图中即使有一个 Broker 挂了,剩余的两个 Broker 依旧能正常工作。这也是分布式系统的常用设计。

同一个 Partition 有多个副本,并分布在不同的 Broker 上,那么 Producer 应该写入到哪一个副本上呢?Consumer 又应该从哪个副本上读取呢?

  1. Kafka 的各个 Broker 需要与 Zookeeper 进行通信,每个 Partition 的多个副本之间通过 Zookeeper 的 Leader 选举机制选出主副本。所有该 Partition 上的读写都通过这个主副本进行。
  2. 其它的冗余副本会从主副本上同步新的消息。就像其它的 Consumer 一样。

小结

本文主要是对 Kafka 的基本概念和结构做了简要介绍,总结如下:

  1. Topic 是顶级概念,对应于一个消息队列。
  2. Kafka 是以 Partition 为单位存储消息的,Consumer 在消费时也是按 Partition 进行的。即 Kafka 会保证一个 Consumer 收到的消息中,来自同一个 Partition 的所有消息是有序的。而来自不同 Partition 的消息则不保证有序。
  3. Partition 会为其中的消息分配 Partition 内唯一的 ID,一般称作偏移量(offset) 。Kafka 会保留所有的消息,直到消息的保留时间(例如设置保留 2 天)结束。这样 Consumer 可以自由决定如何读取消息,例如读取更早的消息,重新消费等。
  4. Kafka 有 Consumer Group 的概念。每个 Group 独立消费某个 Topic 的消息,互相不干扰。事实上,Kafka 会为每个 Group 保存一个偏移量,记录消费的位置。每个 Group 可以包含多个 Consumer,它们共同消费这个 Topic。
  5. 对于一个 Consumer Group,一个 Partition 只能由 Group 中的一个 Consumer 消费。具体哪个 Consumer 监听哪个 Partition 是由 Kafka 分配的。算法可以指定为 Range 或 RoundRobin
  6. 物理上,消息是存在 Broker 上的,一般对应为一台物理机或集群。存储时,每个 Partition 都可以有多个副本。它们会被“均匀”地存储在各个 Broker 中。
  7. 对于一个 Partition,它的多个复本存储一般存储在不同 Broker 中,在同一时刻会由 Zookeeper 选出一个主副本来负责所有的读写操作。

另外,随着 Kafka 的发展,它的定位已经从“分布式消息队列”变成了“分布式流处理平台”,添加了 Connector 及 Stream Processor 的概念。只是这些并不改变它的基本概念和结构。

转载自: https://lotabout.me/2018/kafka-introduction/

耶律齐,一个活成配角的主角

耶律齐是小说《神雕侠侣》中的一个人物,他的经历的前半段拿到任何一部小说里都是主角的命。

从小生活在一个王公贵族的家里,锦衣玉食王孙公子,而且少年时就天赋异禀,还得到一个神秘的绝顶高手传授武功。

成年后家中遭逢巨变,父母被陷害致死,只剩下自己带着妹妹逃出生天,开始流落江湖。

在闯荡的过程中结识了武林盟主的女儿,并且两人情投意合,照一般剧情来说,耶律齐此次应该武功大进,然后杀进蒙古王帐,手刃仇人报仇雪恨。

最后跟意中人隐居塞外,放马牧羊。可惜,后半段剧情没有出现。耶律齐最后的成就也就是在敌国的团练武装势力中做了一个职位还算不错的军官,另外兼职丐帮帮主,而且还是在真正的主角出手相助的情况下。

这作为主角就有点差强人意了。