纪念刘和珍君

正因为他是和我们一样的普通人,所以他的行为格外英雄。 [李文亮医生 事件]


中华民国十五年三月二十五日,就是国立北京女子师范大学为十八日在段祺瑞执政府前遇害的刘和珍杨德群〔2〕两君开追悼会的那一天,我独在礼堂外徘徊,遇见程君〔3〕,前来问我道,“先生可曾为刘和珍写了一点什么没有?”我说“没有”。她就正告我,“先生还是写一点罢;刘和珍生前就很爱看先生的文章。”
这是我知道的,凡我所编辑的期刊,大概是因为往往有始无终之故罢,销行一向就甚为寥落,然而在这样的生活艰难中,毅然预定了《莽原》〔4〕全年的就有她。我也早觉得有写一点东西的必要了,这虽然于死者毫不相干,但在生者,却大抵只能如此而已。倘使我能够相信真有所谓“在天之灵”,那自然可以得到
更大的安慰,——但是,现在,却只能如此而已。
可是我实在无话可说。我只觉得所住的并非人间。四十多个青年的血,洋溢在我的周围,使我艰于呼吸视听,那里还能有什么言语?长歌当哭,是必须在痛定之后的。而此后几个所谓学者文人的阴险的论调,尤使我觉得悲哀。我已经出离愤怒了。我将深味这非人间的浓黑的悲凉;以我的最大哀痛显示于非人间,使它们快意于我的苦痛,就将这作为后死者的菲薄的祭品,奉献于逝者的灵前。

真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血。这是怎样的哀痛者和幸福者?然而造化又常常为庸人设计,以时间的流驶,来洗涤旧迹,仅使留下淡红的血色和微漠的悲哀。在这淡红的血色和微漠的悲哀中,又给人暂得偷生,维持着这似人非人的世界。我不知道这样的世界何时是一个尽头!
我们还在这样的世上活着;我也早觉得有写一点东西的必要了。离三月十八日也已有两星期,忘却的救主快要降临了罢,我正有写一点东西的必要了。

在四十余被害的青年之中,刘和珍君是我的学生。学生云者,我向来这样想,这样说,现在却觉得有些踌躇了,我应该对她奉献我的悲哀与尊敬。她不是“苟活到现在的我”的学生,是为了中国而死的中国的青年。
她的姓名第一次为我所见,是在去年夏初杨荫榆女士做女子师范大学校长,开除校中六个学生自治会职员的时候。〔5〕其中的一个就是她;但是我不认识。直到后来,也许已经是刘百昭率领男女武将,强拖出校之后了,才有人指着一个学生告诉我,说:这就是刘和珍。其时我才能将姓名和实体联合起来,心中却暗自诧异。我平素想,能够不为势利所屈,反抗一广有羽翼的校长的学生,无论如何,总该是有些桀骜锋利的,但她却常常微笑着,态度很温和。待到偏安于宗帽胡同〔6〕,赁屋授课之后,她才始来听我的讲义,于是见面的回数就较多了,也还是始终微笑着,态度很温和。待到学校恢复旧观〔7〕,往日的教职员以为责任已尽,准备陆续引退的时候,我才见她虑及母校前途,黯然至于泣下。此后似乎就不相见。总之,在我的记忆上,那一次就是永别了。

我在十八日早晨,才知道上午有群众向执政府请愿的事;下午便得到噩耗,说卫队居然开枪,死伤至数百人,而刘和珍君即在遇害者之列。但我对于这些传说,竟至于颇为怀疑。我向来是不惮以最坏的恶意,来推测中国人的,然而我还不料,也不信竟会下有残到这地步。况且始终微笑着的和蔼的刘和珍君,更何至于无端在府门前喋血呢?
然而即日证明是事实了,作证的便是她自己的尸骸。还有一具,是杨德群君的。而且又证明着这不但是杀害,简直是虐杀,因为身体上还有棍棒的伤痕。
但段政府就有令,说她们是“暴徒”!
但接着就有流言,说她们是受人利用的。
惨象,已使我目不忍视了;流言,尤使我耳不忍闻。我还有什么话可说呢?我懂得衰亡民族之所以默无声息的缘由了。沉默呵,沉默呵!不在沉默中爆发,就在沉默中灭亡。

但是,我还有要说的话。
我没有亲见;听说,她,刘和珍君,那时是欣然前往的。自然,请愿而已,稍有人心者,谁也不会料到有这样的罗网。但竟在执政府前中弹了,从背部入,斜穿心肺,已是致命的创伤,只是没有便死。同去的张静淑〔8〕君想扶起她,中了四弹,其一是手枪,立仆;同去的杨德群君又想去扶起她,也被击,弹从左肩入,穿胸偏右出,也立仆。但她还能坐起来,一个兵在她头部及胸部猛击两棍,于是死掉了。
始终微笑的和蔼的刘和珍君确是死掉了,这是真的,有她自己的尸骸为证;沉勇而友爱的杨德群君也死掉了,有她自己的尸骸为证;只有一样沉勇而友爱的张静淑君还在医院里呻吟。当三个女子从容地转辗于文明人所发明的枪弹的攒射中的时候,这是怎样的一个惊心动魄的伟大呵!中国军人的屠戮妇婴的伟绩,八国联军的惩创学生的武功,不幸全被这几缕血痕抹杀了。
但是中外的杀人者却居然昂起头来,不知道个个脸上有着血污……。

时间永是流驶,街市依旧太平,有限的几个生命,在中国是不算什么的,至多,不过供无恶意的闲人以饭后的谈资,或者给有恶意的闲人作“流言”的种子。至于此外的深的意义,我总觉得很寥寥,因为这实在不过是徒手的请愿。人类的血战前行的历史,正如煤的形成,当时用大量的木材,结果却只是一小块,但请愿是不在其中的,更何况是徒手。
然而既然有了血痕了,当然不觉要扩大。至少,也当浸渍了亲族;师友,爱人的心,纵使时光流驶,洗成绯红,也会在微漠的悲哀中永存微笑的和蔼的旧影。陶潜〔9〕说过,“亲戚或余悲,他人亦已歌,死去何所道,托体同山阿。”倘能如此,这也就够了。

我已经说过:我向来是不惮以最坏的恶意来推测中国人的。但这回却很有几点出于我的意外。一是当局者竟会这样地凶残,一是流言家竟至如此之下劣,一是中国的女性临难竟能如是之从容。
我目睹中国女子的办事,是始于去年的,虽然是少数,但看那干练坚决,百折不回的气概,曾经屡次为之感叹。至于这一回在弹雨中互相救助,虽殒身不恤的事实,则更足为中国女子的勇毅,虽遭阴谋秘计,压抑至数千年,而终于没有消亡的明证了。倘要寻求这一次死伤者对于将来的意义,意义就在此罢。
苟活者在淡红的血色中,会依稀看见微茫的希望;真的猛士,将更奋然而前行。
呜呼,我说不出话,但以此记念刘和珍君!

如何成事?-读冯唐的《成事》

1、有一个好的身体,身体是革命的本钱,事还没干,人就躺下了,怎么都成功不了,所以说我们要有好的身体,要把锻炼身体作为一种习惯,不知道该干什么的时候,看书和锻炼身体是最好的两个选择,当然冯唐也在书中写了应该如何锻炼身体,这个我们可以对照着练习,其实也很简单,每周集中锻炼三次,每次超过一个小时,要出汗,让后不断地减持下去就好。

2、要专一,冯唐写过《不二》这本书,其实不二这两个字说的就是专一这个道理,专一其实有很多种解释,其实就是一件事一件事的去做,专心致志的做事,不要吃纸碗里的看着锅里的,一次只做一件事情,完成了再去干第二件事情,养成习惯,离成事就近了一步。

3、第三点我觉得应该是埋头干事,只要不死就往死里干,事情做的多了,身体也好了,精神也好了,外面的世界关你屁事,关我屁事,好好干活就行,把手头的活干好了,该休息的时候放肆的休息。冯唐也说,其实现在很多的社会人,其实就是想的太多做的太少,嫌这嫌那,找各种借口,其实就是想偷懒,思想懈怠,要相成事就要埋头苦干。

4、大处着眼、小处着手。这八个字是书中提到最多的八个字,也是曾国藩成事的至理名言,通俗的讲,就是有目标有规划,要通盘考虑,完了以后就是埋头苦干,就是小处着手,从一件一件小事做起,一个一个的做,不能眼高手低。其实曾国藩能够打赢太平天国也是用的这个道理,曾国藩的湘军一开始打仗并不厉害,但是曾国藩就用笨方法,结硬寨打呆仗,就是跟你耗着,慢慢的跟你打,最终取得胜利。

5、要勤快。“百种弊病,皆从懒生”这也是曾国藩的原话,所有的事情都是懒惹的祸。任何时候不要懒,如果从小事开始变的勤快呢?先从早起开始,冯唐在书中说到早起不下十次之多,太阳都能早起,我们为什么不能早起,如果连早起的习惯都不能养成,连早起的毅力都没有,那么这个人肯定不能成事。所以一定要记住“百种弊病,皆从懒生”,勤快从早起开始。

6、另外还要养成一些好的习惯,比如读书、锻炼、定目标、反省等等,多去山里,多去图书馆、多去健身房,吃喝玩乐也要有,但一定要适度,人生短短几十年,如果真想成事,做出一番成就,要养成这些好的习惯,如果天天消耗、夜夜笙歌,一定不是一个能够成事的人。

洗牌算法

-- To shuffle an array a of n elements (indices 0..n-1):
for i from n−1 downto 1 do
     j ← random integer such that 0 ≤ j ≤ i
     exchange a[j] and a[i]

java 实现

import java.util.Arrays;
import java.util.Random;

public class Shuffle {

	public static void shuffle(int[] arr) {
		int i = arr.length;
		Random random = new Random();
		while (i > 1) {
			i = i - 1;
			int j = random.nextInt(i);
			int temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
		System.out.println(Arrays.toString(arr));
	}

	public static void main(String[] args) {
		int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
		for (int i = 0; i < 50; i++)
			shuffle(arr);
	}
}

运行50次结果

[7, 3, 0, 2, 9, 1, 8, 4, 6, 5]
[3, 2, 5, 9, 1, 6, 7, 0, 4, 8]
[7, 8, 6, 1, 4, 2, 0, 9, 5, 3]
[9, 3, 1, 7, 5, 6, 4, 8, 2, 0]
[5, 9, 0, 2, 1, 4, 7, 6, 3, 8]
[4, 8, 3, 9, 6, 1, 5, 0, 2, 7]
[0, 6, 9, 1, 3, 5, 4, 2, 7, 8]
[6, 3, 8, 4, 5, 2, 0, 9, 1, 7]
[8, 9, 3, 1, 4, 7, 6, 2, 0, 5]
[1, 8, 4, 7, 2, 3, 0, 5, 9, 6]
[9, 1, 3, 5, 0, 8, 6, 4, 2, 7]
[1, 7, 9, 4, 6, 3, 8, 0, 5, 2]
[0, 8, 4, 7, 3, 2, 6, 5, 9, 1]
[1, 7, 8, 9, 6, 5, 0, 4, 3, 2]
[5, 4, 1, 8, 0, 7, 3, 2, 9, 6]
[8, 6, 2, 0, 1, 5, 9, 3, 4, 7]
[5, 7, 4, 9, 0, 3, 6, 2, 1, 8]
[8, 9, 5, 4, 7, 0, 1, 3, 2, 6]
[2, 5, 6, 7, 3, 1, 4, 9, 0, 8]
[0, 7, 8, 2, 6, 5, 9, 1, 3, 4]
[4, 3, 6, 0, 5, 1, 2, 9, 8, 7]
[6, 1, 5, 8, 9, 4, 7, 0, 2, 3]
[9, 4, 0, 2, 5, 6, 3, 8, 7, 1]
[5, 2, 7, 0, 4, 3, 9, 6, 1, 8]
[4, 3, 1, 7, 9, 0, 6, 2, 8, 5]
[5, 8, 6, 1, 4, 9, 2, 0, 7, 3]
[3, 0, 2, 6, 1, 5, 8, 7, 9, 4]
[1, 6, 0, 4, 7, 3, 5, 9, 2, 8]
[5, 8, 6, 0, 2, 4, 7, 3, 9, 1]
[8, 7, 3, 6, 4, 1, 0, 9, 2, 5]
[9, 0, 7, 1, 5, 8, 4, 3, 6, 2]
[0, 4, 9, 7, 8, 1, 6, 5, 2, 3]
[5, 0, 4, 2, 1, 7, 9, 8, 3, 6]
[7, 2, 8, 3, 5, 4, 1, 0, 6, 9]
[2, 6, 4, 8, 0, 5, 9, 7, 1, 3]
[0, 2, 9, 7, 8, 6, 1, 4, 3, 5]
[6, 4, 1, 2, 9, 7, 5, 3, 8, 0]
[3, 2, 4, 0, 5, 9, 8, 1, 6, 7]
[9, 0, 8, 7, 6, 2, 3, 4, 1, 5]
[4, 1, 5, 3, 8, 9, 0, 6, 2, 7]
[8, 5, 6, 0, 2, 4, 7, 3, 1, 9]
[1, 4, 9, 6, 3, 2, 8, 7, 0, 5]
[9, 5, 6, 2, 0, 7, 1, 3, 4, 8]
[1, 8, 3, 6, 4, 5, 7, 0, 9, 2]
[8, 3, 7, 5, 1, 9, 0, 2, 4, 6]
[2, 0, 6, 4, 5, 1, 9, 7, 8, 3]
[9, 6, 1, 2, 4, 8, 3, 5, 7, 0]
[6, 3, 4, 0, 2, 1, 8, 9, 5, 7]
[2, 9, 1, 3, 5, 6, 4, 8, 7, 0]
[3, 5, 7, 1, 6, 0, 8, 9, 4, 2]

BackOff重试算法

可以使用斐波那契数列计算重试时间,也可以使用指数补偿计算重试时间。

定义一个接口

@FunctionalInterface
public interface ExponentialBackOffFunction <T> {
	T execute();
}

定义重试工具类

import static java.util.Arrays.asList;

import java.net.SocketTimeoutException;
import java.util.List;

import javax.net.ssl.SSLHandshakeException;

import lombok.extern.log4j.Log4j;

@Log4j
public final class ExponentialBackOff {
	
	private static final int[] FIBONACCI = new int[] { 1, 1, 2, 3, 5, 8, 13 };
	private static final List<Class<? extends Exception>> EXPECTED_COMMUNICATION_ERRORS = asList(
			SSLHandshakeException.class, SocketTimeoutException.class);

	private ExponentialBackOff() {
	}

	// E(c) = Math.pow(2, c) - 1
	// 考虑到补偿时间的均匀分布,补偿时间的数学期望是所有可能性的平均值。
	// 也就是说,在c次冲突之后,补偿时隙数量在 [0,1,...,N] 中,其中 [公式] E(c) = Math.pow(2, c) - 1
	// 则补偿时间的数学期望 E(c) = (Math.pow(2, c) - 1)/2
	public static long getWaitTimeExponential(int attempt) {
		double waitTime = (Math.pow(2, attempt) - 1) / 2;
		return Math.round(waitTime * 100);
	}
	
	// 这个地方使用斐波那契数去增加重试时间
	public static long getWaitTimeDefault(int attempt) {
		return FIBONACCI[attempt] * 100;
	}

	public static <T> T execute(ExponentialBackOffFunction<T> fn) {
		for (int attempt = 0; attempt < FIBONACCI.length; attempt++) {
			try {
				return fn.execute();
			} catch (Exception e) {
				handleFailure(attempt, e);
			}
		}
		throw new RuntimeException("Failed to communicate.");
	}

	private static void handleFailure(int attempt, Exception e) {
		if (e.getCause() != null && !EXPECTED_COMMUNICATION_ERRORS.contains(e.getCause().getClass()))
			throw new RuntimeException(e);
		doWait(attempt);
	}

	private static void doWait(int attempt) {
		try {
			long sleepTime = getWaitTimeExponential(attempt);
			System.out.println("attempt " + attempt + " sleep " + sleepTime);
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
}

测试案例

public class Test {
	public static void main(String[] args) {
		ExponentialBackOff.execute(new Work());
	}
}

class Work implements ExponentialBackOffFunction<String> {

	@Override
	public String execute() {
		int a = 5 / 0;
		return a + "";
	}
}

运行结果

使用指数补偿:
attempt 0 sleep 0
attempt 1 sleep 50
attempt 2 sleep 150
attempt 3 sleep 350
attempt 4 sleep 750
attempt 5 sleep 1550
attempt 6 sleep 3150
使用斐波那契数列
attempt 0 sleep 100
attempt 1 sleep 100
attempt 2 sleep 200
attempt 3 sleep 300
attempt 4 sleep 500
attempt 5 sleep 800
attempt 6 sleep 1300

微服务编排框架

发现一个优秀的微服务编排框架:zeebe

微服务核心研究之–编排

当一个系统采用了微服务架构后,会拆分成很多新的微服务,但原有的业务可能还是没有变化,如何在微服务架构下实现原有的业务?相对于传统架构,微服务架构下更需要通过各微服务之间的协作来实现一个完整的业务流程,可以说服务编排是微服务架构下的必备技能。但是,编排涉及到RPC、分布式事务等等,编排的质量不能仅仅取决于老师傅的手艺,需要有完善的编排框架来支撑。

关于微服务的组合(协调):
编制(Orchestration)—— 面向可执行的流程:通过一个可执行的流程来协同内部及外部的服务交互。通过中心流程来控制总体的目标,涉及的操作,服务调用顺序。
编排(Choreography)—— 面向合作:通过消息的交互序列来控制各个部分资源的交互。参与交互的资源都是对等的,没有集中的控制。

哲学家就餐问题 [go/java 实现练习并发编程]

java

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

class Philosopher implements Runnable{
	private final String name;
	private final ReentrantLock left;
	private final ReentrantLock right;
	private final AtomicInteger hunger = new AtomicInteger(3);
	public Philosopher(String name, ReentrantLock left, ReentrantLock right) {
		this.name = name;
		this.left = left;
		this.right = right;
	}
	@Override
	public void run() {
		while (this.hunger.get() > 0) {
			System.out.println(name + " Hungry");
			this.left.lock();
			this.right.lock();
			System.out.println(name + " Eating");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			this.right.unlock();
			this.left.unlock();
			System.out.println(name + " Thinking");
			this.hunger.decrementAndGet();
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}	
}

public class DiningPhilosopher {
	public static void main(String[] args) {
		ExecutorService executor = Executors.newCachedThreadPool();
		String[] philosophers = new String[] {"Mark", "Russell", "Rocky", "Haris", "Root"};
		ReentrantLock fork0 = new ReentrantLock();
		ReentrantLock forkLeftLock = fork0;
		List<Philosopher> philosopherList = new ArrayList<Philosopher>();
		for(int i=1;i<philosophers.length;i++) {
			String name = philosophers[i];
			ReentrantLock forkRightLock = new ReentrantLock();
			philosopherList.add(new Philosopher(name, forkLeftLock, forkRightLock));
			forkLeftLock = forkRightLock;
		}
		philosopherList.add(new Philosopher(philosophers[0], fork0, forkLeftLock));
		for (Philosopher philosopher : philosopherList) {
			executor.submit(philosopher);
		}
		executor.shutdown();
	}
}

go

package main

import (
	"hash/fnv"
	"log"
	"math/rand"
	"os"
	"sync"
	"time"
)

// 初始化5个人
var ph = []string{"Mark", "Russell", "Rocky", "Haris", "Root"}

const hunger = 3                // 每个哲学家吃几次饭
const think = time.Second / 100 // 思考时间
const eat = time.Second / 100   // 吃饭时间

var fmt = log.New(os.Stdout, "", 0)

var dining sync.WaitGroup

func diningProblem(phName string, dominantHand, otherHand *sync.Mutex) {
	fmt.Println(phName, "Seated")
	h := fnv.New64a()
	h.Write([]byte(phName))
	rg := rand.New(rand.NewSource(int64(h.Sum64())))
	rSleep := func(t time.Duration) {
		time.Sleep(t/2 + time.Duration(rg.Int63n(int64(t))))
	}
	for h := hunger; h > 0; h-- {
		fmt.Println(phName, "Hungry")
		dominantHand.Lock() // 获取资源
		otherHand.Lock()
		fmt.Println(phName, "Eating")
		rSleep(eat)
		dominantHand.Unlock() // 释放资源
		otherHand.Unlock()
		fmt.Println(phName, "Thinking")
		rSleep(think)
	}
	fmt.Println(phName, "Satisfied")
	dining.Done()
	fmt.Println(phName, "Left the table")
}

func main() {
	fmt.Println("Table empty")
	dining.Add(5)
	fork0 := &sync.Mutex{}
	forkLeft := fork0
	for i := 1; i < len(ph); i++ {
		forkRight := &sync.Mutex{}
		go diningProblem(ph[i], forkLeft, forkRight)
		forkLeft = forkRight
	}
	go diningProblem(ph[0], fork0, forkLeft)
	dining.Wait() // 等待结束
	fmt.Println("Table empty")
}

云在青天水在瓶

忙里偷闲终于把大明王朝1566看完了,对政治和经济更加敬畏。分享那些让人听来振聋发聩的语录。

bilibili 1900影剧室 解读

bilibili 史君说剧 讲解

1.三思就是思危 、思退和思变。知道了危险就能躲开危险,这就是“思危”;躲到人家都不再注意你的地方,这就叫思退;退了下来就有机会再慢慢看慢慢想,自己以前哪儿错了,往后该怎么做,这就是思变。

2.不谋全局者,不可谋一隅,不谋一世者,并不可谋一时。

3.这个世上,真靠得住的就两种人,一种是笨人,一种是直人。笨人没有心眼,直人不使心眼。

4.圣人的书是用来读的,用来办事百无一用。

5.任何人答应你的事都不算数,只有自己能做主的才算数。

6.做事情,不问能不能做成,要问应不应该做。

7.这人啊,熬一天不累,熬十天就累了;小心一年不难,小心一辈子就难了。

8.圣人出黄河清,可黄河什么时候清过?黄河虽浊,亦能灌溉;长江虽清,时有泛滥。

9.世间万事万物都只有一个理,各人站的位置不同,看法不同而已。

10.都说人不如旧衣不如新,可在朕看来,衣服和人都是老的好,衣服旧了贴身,人旧了贴心啊。

11.有时离九霄而膺天命 情何以堪;御四海而哀苍生 心为之伤。有时候啊,最亲的不是父子是师徒。儿子将父母之恩视为当然,弟子将师傅之恩,视为报答。

12.只有架起锅子煮白米,不能架起锅子煮道理吧。

13.文官的衣服上绣的是禽,武官的衣服上绣的是兽。披上了这身皮,我们哪一个不是衣冠禽兽。

14.历来造反的都是种田的人,没听说商人能闹翻了天。

15.屋檐滴水代接代,新官不算旧官账。

16.有些事不上秤没四两重,上了秤一千斤打不住。

17.用人之道,贵在知人。两京一十三省的官员,都要靠你们来举荐。有实心用事者,如胡总宪,有顾全大局者,如赵贞吉,这些都是好的。像郑泌昌 何茂才这等硕鼠,竟也荐任封疆,严世藩的两双眼睛,是不是全都瞎了!

18.这个世上,真靠得住的就两种人,一种是笨人,一种是直人。笨人没有心眼,直人不使心眼。

19.人心似水,水是往低处走的,人心总是高了还想高啊!

20.官做的在大,落到底也是居家过日子。

21.平时叫你读读《左传通鉴》,你不以为然;我叫你读一读王阳明的书,你更是不以为然,还说什么半部《论语》可治天下。现在我问你,孔子说的‘知不可为而为之’是什么本意?孔子是告诉世人,做事时不问可不可能,但问应不应该。毁堤淹田,伤天害理,上误国家,下害百姓。这也叫知不可为而为之?

22.朝廷也就是几座宫殿,几座衙门。饭还是要分锅吃的。

23.读书是为了明理,明了理就有了主张,知道该怎么做。但理是在变化的,又不能守死理。

24.圣人出黄河清,可黄河什么时候清过?黄河虽浊,亦能灌溉;长江虽清,时有泛滥。

25.裕王:大明朝谁是贤臣?嘉靖:没有谁是真正的贤臣,贤时用之,不贤黜之。

service mesh

A service mesh is a dedicated infrastructure layer that controls service-to-service communication over a network. It provides a method in which separate parts of an application can communicate with each other. Service meshes appear commonly in concert with cloud-based applications, containers and microservices.

A service mesh is in control of delivering service requests in an application. Common features provided by a service mesh include service discovery, load balancing, encryption and failure recovery. High availability is also common through utilizing software controlled by APIs rather than utilizing hardware. Service meshes can make service-to-service communication fast, reliable and secure.

As an example, an application structured in a microservices architecture might be composed of hundreds of services, all with their own instances operating in a live environment. This could make it challenging for developers to keep track of which components must interact, and make changes to their application if something goes wrong. Including communication protocols in a service rather than in a separate and dedicated layer would make the process of keeping track and making changes to an application fairly complex. Utilizing a service mesh allows developers the ability to separate service-to-service communication into a dedicated layer.

An organization may choose to utilize an API gateway, which handles protocol transactions, over a service mesh. However, developers must update the API gateway every time a microservice is added or removed.

How a service mesh works
A service mesh architecture uses a proxy instance called a sidecar in whichever development paradigm is in use, commonly containers and/or microservices. In a microservice application, a sidecar will attach to each service. In a container, the sidecar is attached to each application container, VM or container orchestration unit, such as a Kubernetes pod.

Sidecars can handle tasks abstracted from the service itself, such as monitoring and security.

Service instances, sidecars and their interactions make up what is called the data plane in a service mesh. A layer called the control plane manages tasks such as creating instances, monitoring and implanting policies, such as network management or network security policies. Control planes can connect to a CLI or a GUI interface for application management.

Service mesh benefits and drawbacks
A service mesh addresses some large issues with managing service-to-service communication, but not all. Some advantages of a service mesh include:

Simplifies communication between services in both microservices and containers.
Easier to diagnose communication errors, since they would occur on their own infrastructure layer.
Supports security features such as encryption, authentication and authorization.
Allows for faster development, testing and deployment of an application.
Sidecars placed next to a container cluster is effective in managing network services.
Some downsides to service meshes include:

Runtime instances increase by utilizing a service mesh.
Adds an extra step where each service call must first run through the sidecar proxy.
Service meshes do not address issues such as integrating with other services or systems and routing type or transformation mapping.
The service mesh market
A service mesh is commonly available as an open source technology from diverse creators. It can also be consumed as a service from major cloud providers.

Istio is an open source service mesh provided by Google, IBM and Lyft. Istio is designed as a universal control plane first targeted for Kubernetes deployments, but can be used on multiple platforms. Its data plane relies on proxies called Envoy sidecars. This service mesh features security measures such as identity and key management. It also supports fault injection and hybrid deployment.

Istio service mesh
The Istio service mesh architecture is one of the major designs available.
Linkerd is another open source, multiplatform service mesh. Linkerd was developed by Buoyant and is built on Twitter’s Finagle library. This service mesh supports platforms such as Kubernetes, Docker and Amazon ECS. Features include built-in service discovery and control plane, Namerd.

Goroutines vs Threads

Here are some of the advantages of Goroutines over threads:

You can run more goroutines on a typical system than you can threads.
Goroutines have growable segmented stacks.
Goroutines have a faster startup time than threads.
Goroutines come with built-in primitives to communicate safely between themselves (channels).
Goroutines allow you to avoid having to resort to mutex locking when sharing data structures.
Goroutines are multiplexed onto a small number of OS threads, rather than a 1:1 mapping.
You can write massively concurrent servers withouth having to resort to evented programming.

You can run more of them
On Java you can run 1000’s or tens of 1000’s threads. On Go you can run hundreds of thousands or millions of goroutines.

Java threads map directly to OS threads, and are relatively heavyweight. Part of the reason they are heavyweight is their rather large fixed stack size. This caps the number of them you can run in a single VM due to the increasing memory overhead.

Go OTOH has a segmented stack that grows as needed. They are “Green threads”, which means the Go runtime does the scheduling, not the OS. The runtime multiplexes the goroutines onto real OS threads, the number of which is controlled by GOMAXPROCS. Typically you’ll want to set this to the number of cores on your system, to maximize potential parellelism.

They let you avoid locking hell
One of the biggest drawback of threaded programming is the complexity and brittleness of many codebases that use threads to achieve high concurrency. There can be latent deadlocks and race conditions, and it can become near impossible to reason about the code.

Go OTOH gives you primitives that allow you to avoid locking completely. The mantra is don’t communicate by sharing memory, share memory by communicating. In other words, if two goroutines need to share data, they can do so safely over a channel. Go handles all of the synchronization for you, and it’s much harder to run into things like deadlocks.

No callback spaghetti, either
There are other approaches to achieving high concurrency with a small number of threads. Python Twisted was one of the early ones that got a lot of attention. Node.js is currently the most prominent evented frameworks out there.

The problem with these evented frameworks is that the code complexity is also high, and difficult to reason about. Rather than “straightline” coding, the programmer is forced to chain callbacks, which gets interleaved with error handling. While refactoring can help tame some of the mental load, it’s still an issue.

Golang 的 goroutine 是如何实现的?