2019-04-06 一读

个人隐私是穷人多交的税
阅读原文
低收入群体工作环境多有各种监控,雇主通过各种手段收集他们的个人信息;同时他们对信息安全/互联网个人隐私的知识比较匮乏,一不留神就把自己所有资料都贡献出去了。
贡献出大量个人信息的坏处:被各种机构用来拒绝你的依据;被各种广告精准定位。

Application logging best practices
阅读原文
别 log 太多信息,也别 log 太少;log 要有结构化;要用对 log 的等级,info 级的 log 千万不能把熟睡中的 oncall 的工程师吵醒;别因为 log 而影响了整体性能。

Google 频繁地放弃产品,对其品牌是巨大的损害
阅读原文
Google 规模庞大,做了很多产品,也放弃了很多产品。该不该投入时间精力去使用 Google 的新产品?或许用到明年就下线了?反方观点:Google 做得对,互联网思维,快速迭代,果断放弃没人用的产品,把人力资源分配到更有价值的产品上。

From Show HN to Series D
阅读原文
Segment 创始人 cto 讲述他们的创业故事。6年半以前创业几乎失败,死马当活马医地在 Hacker News 分享了一个 400 行的开源 js 文件,现如今融了 D 轮,估值 $15 亿。
在 Hacker News 上分享了项目,最后做大的例子还有不少。最有名的当属 Dropbox (2007年4月4日)与 Redis(2009年2月25日)了。

Jack Dorsey:只用 iPhone,管理两家上市公司
阅读原文
Jack Dorsey 唯一的计算设备是 iPhone,不管是家里还是工作,都没有 PC。作为两家上市公司的 CEO,好像也没有什么使用 PC 的地方。计算设备的主要作用就是发邮件,简单记事本,刷 Twitter。

2019-04-05 一读

艺多不压身对于创业者是个谬论,学的多不一定更好
阅读原文
JotForm创始人的文章,关于爱学习的人怎么面对信息过载。讲的是“学得多不一定更好”,读完感觉醍醐灌顶。对于成年人来说,艺多不压身,但什么都学,什么都做却分心也花精力。对于创业者来说,花太多时间去阅读,研究,学习,仿佛成了新的“高效拖延症”。过度学习让人感觉良好,不如多实践,出活。
感谢 Vicki Zhou 的投稿。

How to Make Wealth
阅读原文
这是 Paul Graham 在黑客与画家一书中的文章,写于创办 YC 之前、把公司卖给 Yahoo 财富自由之后,那个阶段正是他哲学家+创业/人生导师的人设成型的初期。
程序员如何致富?湾区初级程序员在公司上班,今年每天实际写代码时间仅有1、2小时,但年薪至少十几万刀起跳;公司付得起十几万,意味着一个初级程序员创造的价值至少也是十几万一年。如果初级程序员辞职了,不用开会、不用搞办公室政治、工作效率提高30倍,是不是一年就能至少赚300多万?这个逻辑如何?阅读原文。

Return On Luck
阅读原文
出生在1950年代、有钱白人家庭、中学就接触电脑编程、理科学得很好、就读藤校的美国人肯定不止 Bill Gates 一人,为啥他取得巨大成功了?
微软一开始是成立于新墨西哥州的 Albuquerque 做 Altair 电脑上的 Basic 解释器的小公司。如果你是风投,你会投资1975年的微软吗?Altair 一共生产了几台电脑?全世界有多少人需要用 Basic 解释器?市场能有多大?为什么公司在盛产外星人的新墨西哥州?
每个人的运气都是一种资本,不同的人拥有相同分量的运气,最终不同人取得的回报大小也不同。

公司每个员工相同薪水
阅读原文
二十个员工,远程办公,不同地区、不同职能,薪水都相同。这么做的好处与坏处?

寓言故事:两个程序员
阅读原文
从前有俩程序员分别在两家公司实现相同的系统。一人悠哉地写了精简的程序,实现所有需求提前完工,管理层觉得活太简单,颇为不爽;另一人虚张声势拉扯多人团队做超复杂的系统,实现多数需求,管理层以为活太复杂却能按时完工,实属不易,给予重赏。

JAVA面试题

为什么很多编程语言中数组都从0开始编号:

从 1 开始编号,每次随机访问数组元素都多了一次减法运算,对于 CPU 来说,就是多了一次减法指令。

数组作为非常基础的数据结构,通过下标随机访问数组元素又是其非常基础的编程操作,效率的优化就要尽可能做到极致。所以为了减少一次减法操作,数组选择了从 0 开始编号,而不是从 1 开始。

说数组起始编号非 0 开始不可。所以我觉得最主要的原因可能是历史原因。

C 语言设计者用 0 开始计数数组下标,之后的 Java、JavaScript 等高级语言都效仿了 C 语言,或者说,为了在一定程度上减少 C 语言程序员学习 Java 的学习成本,因此继续沿用了从 0 开始计数的习惯。实际上,很多语言中数组也并不是从 0 开始计数的,比如 Matlab。甚至还有一些语言支持负数下标,比如 Python。

JVM标记清除算法:

大多数主流虚拟机采用可达性分析算法来判断对象是否存活,在标记阶段,会遍历所有 GC ROOTS,将所有 GC ROOTS 可达的对象标记为存活。只有当标记工作完成后,清理工作才会开始。

不足:1.效率问题。标记和清理效率都不高,但是当知道只有少量垃圾产生时会很高效。2.空间问题。会产生不连续的内存空间碎片。

数据结构与算法之美学习12

排序(下):如何用快排思想在O(n)内查找第K大元素

归并排序

第一,归并排序可以是稳定的排序算法。
第二,归并排序的时间复杂度是 O(nlogn)
第三,归并排序的空间复杂度任何情况下都是 O(nlogn),它有一个致命的“弱点”,那就是归并排序不是原地排序算法。最大空间复杂度是 O(n)。

快速排序

快速排序不是原地排序算法
快速排序并不是一个稳定的排序算法。
快排的时间复杂度在大部分情况下的时间复杂度都可以做到 O(nlogn),只有在极端情况下,才会退化到 O(n2)。

内容小结

归并排序和快速排序是两种稍微复杂的排序算法,它们用的都是分治的思想,代码都通过递归来实现,过程非常相似。理解归并排序的重点是理解递推公式和 merge() 合并函数。同理,理解快排的重点也是理解递推公式,还有 partition() 分区函数。

归并排序算法是一种在任何情况下时间复杂度都比较稳定的排序算法,这也使它存在致命的缺点,即归并排序不是原地排序算法,空间复杂度比较高,是 O(n)。正因为此,它也没有快排应用广泛。

快速排序算法虽然最坏情况下的时间复杂度是 O(n2),但是平均情况下时间复杂度都是 O(nlogn)。不仅如此,快速排序算法时间复杂度退化到 O(n2) 的概率非常小,我们可以通过合理地选择 pivot 来避免这种情况。

突破网站复制粘贴的限制

第一步,复制以下代码

1
javascript:(function() { function R(a){ona = "on"+a; if(window.addEventListener) window.addEventListener(a, function (e) { for(var n=e.originalTarget; n; n=n.parentNode) n[ona]=null; }, true); window[ona]=null; document[ona]=null; if(document.body) document.body[ona]=null; } R("contextmenu"); R("click"); R("mousedown"); R("mouseup"); R("selectstart");})()

第二步:以chrome谷歌浏览器为例

  • 打开chrome的书签,点开书签管理器,右键添加网页。
  • 名称这里写上点我破解网页复制,网址上粘贴楼上的代码。确定就可以了。
  • 遇到不能复制的网页,点一下这条书签,OK可以复制了!

https://www.jianshu.com/p/a93fca575716
https://gist.github.com/Rand01ph/8dfa9a0ea396e560ac0f97373c863631

Mysql数据实时同步到Elasticsearch

1. Mysql安装

在某些情况下,我们只需要 MySQL 的客户端,而不需要完整的MySQL服务器。比如当你需要连接到远程的 MySQL 服务器的时候。

如果只需安装客户端的话,可以使用命令:

1
yum install mysql

如果需要安装Mysql服务,使用如下命令:

1
yum install mysql-server

将Mysql的日志格式改为row
日志格式可以再mysql运行时改变

1
mysql> SET GLOBAL binlog_format = 'ROW';

参考 https://dev.mysql.com/doc/refman/5.6/en/binary-log-setting.html

2. 安装go

安装Go(1.9+)并设置你的GOPATH

3.go-mysql-elasticsearch

go-mysql-elasticsearch可以将MySQL数据自动实时同步到Elasticsearch。

它首先用于mysqldump获取表中已有的数据,然后根据binlog将表的所有操作同步到ES。

数据的插入,更新,删除和增加字段操作,都可以及时同步到ES,ES索引中的字段可以比mysql中多。

安装
1
git clone https://github.com/siddontang/go-mysql-elasticsearch.git

将其下载到服务器,它会在控制台中打印一些消息,跳过它。:-)

1
2
cd /path/to/go-mysql-elasticsearch
make

如何使用
  • 在MySQL中创建表。
  • 如果可能,创建关联的Elasticsearch索引,文档类型和映射,否则,Elasticsearch将自动创建这些索引。
  • 配置库,请参阅示例config river.toml
  • 在配置文件中设置MySQL源,请参阅下面的source
  • 在配置文件中自定义MySQL和Elasticsearch映射规则,请参阅下面的规则
  • 启动 ./bin/go-mysql-elasticsearch -config=./etc/river.toml
提示
  • MySQL支持的版本<8.0
  • ES支持的版本<6.0(其实ES6.4.1也基本可以用)
  • binlog format必须是row
  • 无法在运行时更改表结构。(经过验证,其实是可以的)
  • 将同步的MySQL表应该有PK(主键),现在允许多列PK,例如,如果PK是(a,b),将使用“a:b”作为键。PK数据将在Elasticsearch中用作“id”。您还可以使用其他列作为ID的组成部分。
  • 你应首先在Elasticsearch中创建关联的mapping,我不认为使用默认mapping是明智的决定,你必须知道如何更好更精确的搜索。
  • mysqldump 必须与go-mysql-elasticsearch存在于同一节点中(所以至少要安装mysql客户端),否则,go-mysql-elasticsearch将仅尝试同步binlog。
  • 不要在一个SQL中同时更改太多行。
Source

在go-mysql-elasticsearch中,您必须确定要在源配置中将哪些表同步到elasticsearch。

etc/river.toml 配置文件中的格式如下:

1
2
3
4
5
6
7
[[source]]
schema = "test"
tables = ["t1", t2]

[[source]]
schema = "test_1"
tables = ["t3", t4]

schema是数据库名称,tables包括需要同步的表。
如果要同步数据库中的所有表,可以使用星号(*)。

1
2
3
4
5
[[source]]
schema = "test"
tables = ["*"]
# When using an asterisk, it is not allowed to sync multiple tables
# tables = ["*", "table"]

Rule

默认情况下,go-mysql-elasticsearch将使用MySQL表名作为Elasticserach的索引和类型名称,使用MySQL表字段名作为Elasticserach的字段名。
例如,如果一个名为blog的表,默认索引和Elasticserach中的类型都被命名为blog,如果表字段名为title,则默认字段名也称为title。

注意:go-mysql-elasticsearch将使用ES索引和类型的小写名称。例如,如果您的表名为BLOG,则ES索引和类型都被命名为blog。

Rule 可以让您更改此名称映射。配置文件中的规则格式如下:

1
2
3
4
5
6
7
8
9
10
11
[[rule]]
schema = "test"
table = "t1"
index = "t"
type = "t"
parent = "parent_id"
id = ["id"]

[rule.field]
mysql = "title"
elastic = "my_title"

在上面的示例中,我们将使用新索引并键入名为“t”而不是默认“t1”,并使用“my_title”而不是字段名称“title”。

Rule field types

为了在不同的elasticsearch类型上映射mysql列,您可以按如下方式定义字段类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[[rule]]
schema = "test"
table = "t1"
index = "t"
type = "t"

[rule.field]
// This will map column title to elastic search my_title
title="my_title"

// This will map column title to elastic search my_title and use array type
title="my_title,list"

// This will map column title to elastic search title and use array type
title=",list"

// If the created_time field type is "int", and you want to convert it to "date" type in es, you can do it as below
created_time=",date"

修饰符“list”将mysql字符串字段,如”a,b,c“,转换成elastic数组类型“{”a“,”b“,”c“}’,如果您需要在这些字段上做filter查询,这将非常有用。

Wildcard table

go-mysql-elasticsearch只允许你确定要同步哪个表,但有时候,如果你把一个大表分成多个子表,比如1024,table_0000,table_0001,… table_1023,那么很难为每个表编写规则。

go-mysql-elasticserach支持使用通配符表,例如:

1
2
3
4
5
6
7
8
9
[[source]]
schema = "test"
tables = ["test_river_[0-9]{4}"]

[[rule]]
schema = "test"
table = "test_river_[0-9]{4}"
index = "river"
type = "river"

“testriver [0-9] {4}”是通配符表定义,表示“test_river_0000”到“test_river_9999”,同时规则中的表必须与它相同。

在上面的示例中,如果您有1024个子表,则所有表将同步到Elasticsearch,索引为“river”并键入“river”。

Filter fields

您可以使用filter同步指定的字段,例如:

1
2
3
4
5
6
7
[[rule]]
schema = "test"
table = "tfilter"
index = "test"
type = "tfilter"
# Only sync following columns
filter = ["id", "name"]

在上面的例子中,我们只会同步MySQL表tfiler的列id和name到Elasticsearch。

忽略没有主键的表

当您在没有主键的情况下同步表时,您可以看到以下错误消息。

1
schema.table must have a PK for a column

您可以在配置中忽略这些表,如:

1
2
# Ignore table without a primary key
skip_no_pk_table = true

Elasticsearch Pipeline

您可以使用Ingest Node Pipeline在索引之前预处理文档,例如JSON字符串解码,合并文件等。

1
2
3
4
5
6
7
8
[[rule]]
schema = "test"
table = "t1"
index = "t"
type = "_doc"

# pipeline id
pipeline = "my-pipeline-id"

节点:您应该手动创建管道并且Elasticsearch> = 5.0。

Why not other rivers?

虽然Elasticsearch还有其他一些MySQL同步工具,比如elasticsearch-river-jdbcelasticsearch-river-mysql,作者还是想用Go新写了,为什么?

  • 自定义,我想决定要同步哪个表,关联的索引和类型名称,甚至Elasticsearch中的字段名称。
  • 使用binlog进行增量更新,并且可以在服务再次启动时从上次同步位置恢复。
  • 一个通用的同步框架,不仅适用于Elasticsearch,也适用于其他内容,如memcached,redis等……
  • 通配符表支持,我们有很多子表,如table_0000 - table_1023,但是想要使用唯一的Elasticsearch索引和类型。

参考
https://github.com/siddontang/go-mysql-elasticsearch
https://leonax.net/p/4345/install-mysql-client-on-linux/

初见Kafka Stream

kafka stream架构
https://docs.confluent.io/current/streams/architecture.html#parallelism-model

kafka stream应用入门教程
https://kafka.apache.org/21/documentation/streams/tutorial

参数num.stream.threads
The number of threads to execute stream processing.
默认只使用一个线程。

https://docs.confluent.io/current/streams/developer-guide/config-streams.html#streams-developer-guide-optional-configs

多实例部署
https://docs.confluent.io/current/streams/faq.html#streams-faq-scalability-maximum-parallelism

注意

使用官方的例子的时候,可能会出现时间戳的错误,这时候自定义一个类,如下:

1
2
3
4
5
6
7
8
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.streams.processor.TimestampExtractor;
public class DefaultEventTimeExtractor implements TimestampExtractor {
@Override
public long extract(ConsumerRecord<Object, Object> record, long previousTimestamp) {
return System.currentTimeMillis();
}
}

然后在主类中进行如下设置:

1
props.put(StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, DefaultEventTimeExtractor.class.getName());

《数据结构与算法之美》学习02

数组和链表

数组需要一块连续的内存空间来存储,对内存的要求比较高。如果我们申请一个 100MB 大小的数组,当内存中没有连续的、足够大的存储空间时,即便内存的剩余总可用空间大于 100MB,仍然会申请失败。

而链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用,所以如果我们申请的是 100MB 大小的链表,根本不会有问题。

最常见的链表结构,它们分别是:单链表、双向链表和循环链表。

如何基于链表实现 LRU 缓存淘汰算法?

思路是这样的:我们维护一个有序单链表,越靠近链表尾部的结点是越早之前访问的。当有一个新的数据被访问时,我们从链表头开始顺序遍历链表。

  1. 如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。

  2. 如果此数据没有在缓存链表中,又可以分为两种情况:

如果此时缓存未满,则将此结点直接插入到链表的头部;

如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。

回文串

“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。

Hive Metastore服务异常

1
The health test result for HIVEMETASTORE_PAUSE_DURATION has become bad: Average time spent paused was 37.7 second(s) (62.80%) per minute over the previous 5 minute(s). Critical threshold: 60.00%.
1
The health test result for HIVE_HIVEMETASTORES_HEALTHY has become bad: Healthy Hive Metastore Server: 0. Concerning Hive Metastore Server: 0. Total Hive Metastore Server: 1. Percent healthy: 0.00%. Percent healthy or concerning: 0.00%. Critical threshold: 51.00%.

最近每天早晚都会收到这样的hive报警,今天google了一下,看cloudera上有人回答,应该是hive metastore的内存不足引起的,看了一下CDH manager上 Hive Metastore Server的Charts Library下的JVM Heap Memory Usage,发现使用率基本都是98%以上。嗯,应该是分配给hive metastore的内存太小了,从574M调到了2G。这两天观察一下。

凡是CDH PAUSE_DURATION相关的报警,应该都是java heap不够引起的。因为这个时候jvm在做GC,无法做其他响应。

参考 https://webcache.googleusercontent.com/search?q=cache:C3NJR-GjfPkJ:https://community.cloudera.com/t5/Batch-SQL-Apache-Hive/hive-server-2-pause-duration/m-p/57000+&cd=1&hl=zh-CN&ct=clnk&gl=hk 需要翻墙才能看到,并且这是google的缓存

以下是上边参考链接的文字内容:

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
26
27
28
hive server 2 pause duration

sim6
Expert Contributor
7/5/17
Pause DurationSuppress...
Average time spent paused was 46.4 second(s) (77.32%) per minute over the previous 5 minute(s). Critical threshold: 60.00%
 
I have suddenly started getting this issue. It never used to happen before. Have not even changed any configurations. What could be the possible reasons and how to inspect and resolve this?
Labels:
Cloudera Manager
Hive
Add Comment
Kudo 0

mbigelow
Champion
7/5/17
This is a garbage collection (GC) pause. A GC trigger will depend on the type of GC in use for HS2. An obvious trigger that you can detect is that the heap was too full. Go the HiveServer2 role an click Chart Library. It typically defaults to the Process Resources charts, if not go there. You should see the JVM Heap Memory Usage and GC pause charts. If the heap is constantly high (70% or above) then that is the likely reason. In that case the solution could be a simple as increasing the HS2 heap.

Note: the heap will increase as usage increases. So you could just have more concurrent or larger queries being processed by HS2.
Add Comment
Kudo 1

sim6
Expert Contributor
7/6/17
I have increased the heap size. It was set to default of 256 MB which I guess was causing the problem. I will revert if it keeps working alright :) Thanks much for your response .It helped

《数据结构与算法之美》学习01

刚才听了几节极客时间的《数据结构与算法之美》,其中《05 | 数组:为什么很多编程语言中数组都从0开始编号?》一节讲了从0开始编号的原因,并且在课后留了两个问题,1.回顾下标记清除垃圾回收算法,2.二维数组的内存寻址公式是怎样的。看了评论区的内容,大开眼界,非常精彩,通俗易懂的把这两个问题说清楚了,之前看书的时候可能还一点疑惑,现在明白了,评论区真是高手如云。

从0开始编号的原因,主要是以下两个:

从 1 开始编号,每次随机访问数组元素都多了一次减法运算,对于 CPU 来说,就是多了一次减法指令。

数组作为非常基础的数据结构,通过下标随机访问数组元素又是其非常基础的编程操作,效率的优化就要尽可能做到极致。所以为了减少一次减法操作,数组选择了从 0 开始编号,而不是从 1 开始。

说数组起始编号非 0 开始不可。所以我觉得最主要的原因可能是历史原因。

C 语言设计者用 0 开始计数数组下标,之后的 Java、JavaScript 等高级语言都效仿了 C 语言,或者说,为了在一定程度上减少 C 语言程序员学习 Java 的学习成本,因此继续沿用了从 0 开始计数的习惯。实际上,很多语言中数组也并不是从 0 开始计数的,比如 Matlab。甚至还有一些语言支持负数下标,比如 Python。

JVM标记清除算法:

大多数主流虚拟机采用可达性分析算法来判断对象是否存活,在标记阶段,会遍历所有 GC ROOTS,将所有 GC ROOTS 可达的对象标记为存活。只有当标记工作完成后,清理工作才会开始。

不足:1.效率问题。标记和清理效率都不高,但是当知道只有少量垃圾产生时会很高效。2.空间问题。会产生不连续的内存空间碎片。

二维数组内存寻址:

对于 m n 的数组,a [ i ][ j ] (i < m,j < n)的地址为:
address = base_address + ( i
n + j) * type_size