Thursday, December 20, 2018

Ant



https://blog.mikeski.net/blog_post/30
Ivy “Impossible to Acquire Lock”
Easy way to get IVY to release all locks.
find ~/.ivy -name '*.lck' -exec rm -f {} \;

https://stackoverflow.com/questions/25701740/java-thread-dump-waiting-on-object-monitor-what-is-it-waiting-on
Java thread dump: WAITING (on object monitor) - what is it waiting on?

It's a peculiarity of HotSpot JVM. When dumping a stack, JVM recovers the wait object from the method local variables. This info is available for interpreted methods, but not for compiled native wrappers.
When Object.wait is executed frequently enough, it gets JIT-compiled.
After that there will be no "waiting on" line in a thread dump.
  1. Since wait() must be called on a synchronized object, most often the wait object is the last locked object in the stack trace. In your case it is
    - locked <0x00007f98cbebe5d8> (a com.tibco.tibjms.TibjmsxResponse)
    
  2. To prevent Object.wait from being JIT-compiled (and thus making wait info always available) use the following JVM option
    -XX:CompileCommand="exclude,java/lang/Object.wait" 
    

https://issues.gradle.org/browse/GRADLE-1723
       :::: ERRORS
               impossible to acquire lock for org.grails#grails-docs;1.3.6
find ~/.gradle/caches/artifacts/ -name "*.lck" 
/home/davide/.gradle/caches/artifacts/asm/asm-util/wharfdata-3.2.kryo.lck
Removing it while a milestone-4 process was hanging, it continued soon with no problems.

https://stackoverflow.com/questions/25039864/specifying-jvm-arguments-in-ant-tasks
You can set ANT_OPTS parameters. For example in Windows
SET ANT_OPTS=-Xmx1024m -XX:MaxPermSize=256m
or just use maxmemory attribute of junit ant task (http://ant.apache.org/manual/Tasks/junit.html):
<junit maxmemory="1024m" ...
<junit printsummary="true" fork="yes" haltonfailure="false" failureproperty="junitsFailed" errorProperty="junitsFailed">
    <jvmarg value="-Xmx1024m"/>
    <jvmarg value="-Duser.timezone=GMT0"/>
</junit>

Tuesday, November 13, 2018

Service Discovery



https://medium.com/airbnb-engineering/smartstack-service-discovery-in-the-cloud-4b8a080de619
http://allenlsy.com/service-discovery-with-smartstack
一个解决方案就是,能通过自动化的办法来解决以上问题。这个解决方案需要做到:
  • 一个 server 起来后,它立刻就能够接收所属 service 的请求
  • 能够为整个 service 做 load balancing
  • server 出问题时,能自动停止分配 request 给这台 server
  • 移除一台 server 不会影响整个 service 的正常工作。这样还能提高 debugibility
  • 能提供 observibility,保证工程师能够看到 service 的工作情况, server 的情况
  • 改变 service 的配置时,需要的人工干涉能够尽量少,比如添加一个 service ,添加一台 server
  • 不要有 single point of failure


不符合要求的解决方案

有两个方案看似能够解决问题,实际上是不行的。我们先来看看它们的问题。

DNS

把服务按照 subdomain 来划分。新添加一台 server 时,直接增加一个 DNS record。这样 request 到来时,DNS 可以随机分配 request 到其下的 server。
这个方案的主要问题是:
  1. DNS 的解析是会被 client 缓存住的。如果 server 发生改变, client 需要刷新缓存,否则还是可能把 request 发送到已经 down 了的 server 上。这增加了 service 的不确定性。而其实,在整个架构的各个环节,只要有 component 缓存了这个 DNS 的解析,都会出问题,而且很难 debug
  2. 另外,DNS 这种随机分配的方式还不同于 round robin。它的 load balancing 方面不保证把 request 发给相对空闲的 server。

Load Balancer

如果使用全局的 load balancer,也就是说, services 之间的请求,都要通过 load balancer 来进行路由。每个 service 只需要保证能联络 load balancer 就行了。如何做到这一点呢?你可能会想到通过 DNS。但这样并没解决问题。如果 load balancer down了,你还是需要通过配置 DNS 来路由到另一台 load balancer。而 DNS 的问题(比如随机分配)在上面已经讲过了。

在 app 内做 Service 注册和发现

一个流行的解决方案,就是把这个 service 注册和发现的逻辑写进 app 的代码里面。在 Airbnb ,从前在一些 java app 里写了 service 注册逻辑。使用 Zookeeper 来管理所有 service。Zookeeper 拥有一份后端所有 services 的列表。service 间歇性的向 zookeeper 请求这份列表,来获得其他 services 的信息。
这个方案也有些问题。Zookeeper 对非 JVM 语言的支持并不好。对那些语言,需要自己写 zookeeper client。有时候甚至需要支持其他团队的项目,也就是说不是你本人写的,你只是负责配置。这也会带来麻烦。
Airbnb 开发的这个 SmartStack,把这个 service discovery 的问题和 app 本身完全独立出来。它由两个部分组成: Nerve 用来做 service registration,Synapse 用来做 service discovery。这两个部分变成两个 app 和主 app 部署在一起。

Nerve

Nerve 负责把自己 app 的信息发给 Zookeeper。这与 java zookeeper client 很相似。
而在注册自己之前, Nerve 有一个 health checklist 需要检测。只有当所有 health check 都通过,才能注册自己。这也就要求,所有 service 都实现了被 health check 的功能。

Synapse

Synapse 实现 service discovery 的办法是,通过从 Zookeeper 获取其他 services 的信息,在本地配置并运行了一个 HAProxy。由这个HAProxy 来负责 routing request 这件事情。
这其实就是把一个 centralised load balancer 变成了 decentralised。app 的 load balancer 之间在 localhost 运行了,所以也不存在找不到的情况。Synapse 其实只是一个中间进程,和 HAProxy独立。如果 Synapse down 了, app 不能获得 services 信息的更新,但从前的信息还在 HAProxy。通过这种工作方式,还实现了强大的 logging 功能,复杂的 routing 算法,队列算法, retry 机制, timeout 机制。
当其他 service 信息发生改变的时候,Synapse 会重新生成 HAProxy 配置文件,并重启 HAProxy。其他 service down 的时候, Synapse 会把对应的 HAProxy 的 stats socket 变成维护模式。

使用 SmartStack 的好处

  • Zookeeper 会间歇性对 service 做 health check。一旦 service 可用,Zookeeper 会通知其他 server 的 Synapse
  • 如果 server 出现问题,在下一次 health check 时会被 Zookeeper 发现
  • Synapse 接收到 Zookeeper 的更新后会重新生成 HAProxy 配置文件,然后重新读入配置文件,而不需要重启 HAProxy。因此这个过程非常快
  • 关闭 Nerve 即可从集群移除一台 server
  • 通过 HAProxy 的管理页面可以看到各台 server 的状态,observibility
  • 架构是基于 Zookeeper 搭建的,是 robust 分布式系统

Postgresql Advanced Usage



https://medium.com/namely-labs/syncing-cache-with-postgres-7a4d78cec022
since we really only care about updating the cache when the database is updated, we can let the database itself update the caches by broadcasting when a change has been made. Postgresql provides functionality for a publish-subscribe pattern called LISTEN/NOTIFY. Like any pub-sub implementation, LISTEN/NOTIFY allows you to set channels on which the database can broadcast some text. Others can then listen on those channels and receive information asynchronously. Postgresql stores all the NOTIFY’s in a queue and drops them only when all registered listeners have received them. It is something to keep in mind because that queue can fill up if a listener fails which will cause an error in Postgresql on the next notify. Lastly, we can build a simple trigger in Postgresql that will NOTIFY on inserts to a table.


For example, let’s say we have an application that keeps track of employees and the departments they belong to. Each department has an employee designated as the manager of that department. For processing purposes, it’d be helpful if we kept a directory in memory of all the employees and who their department manager is.

CREATE OR REPLACE FUNCTION new_hire_notify() RETURNS trigger AS $$
  DECLARE
    payload varchar;
    mid uuid;
  BEGIN
    SELECT manager_id INTO mid FROM departments
    WHERE id=NEW.department;
    payload = CAST(NEW.id AS text) ||
    ‘, ‘ || CAST(mid AS text);
    PERFORM pg_notify(‘new_hire’, payload);
    RETURN NEW;
  END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER value_insert
AFTER INSERT
ON employees
FOR EACH ROW
  EXECUTE PROCEDURE new_hire_notify();

Then we create a new listener connection, which is a separate TCP connection to Postgresql. On that connection, we can then specify channels to listen to. We can subscribe to multiple channels on the same listener by calling listener.Listen on as many channels as we need. Finally, we pass the listener to the Cache.Listen method, and spin it off into a Go routine. 

https://simongui.github.io/2016/12/02/improving-cache-consistency.html
MySQL has a binlog replication protocol which is used for primary/secondary replication. This is essentially a replicated queue that has all the transactions recorded in-order as shown in Figure 4.
This isn’t a popular solution but I say, why not? It works very well. You can write an application that can speak the MySQL binlog replication protocol that consumes the binlog entries and execute SET operations against the cache service(s). There are two ways you could consume the binlog data.
  • Interpret the raw SQL syntax and issue SET operations.
  • The web application embeds cache keys as a comment in the SQL.


Both of these options are good because you can even get the transaction scope of each transaction in the binlog statements if you need to and if the target system supports atomic multi-set operations. I prefer the 2nd option because it’s easier to parse and the application already has this information in most cases.
https://stackoverflow.com/questions/1772810/is-there-any-way-to-let-mysql-server-push-db-updates-to-a-client-program
For an actively connected client interested in cache invalidation techniques:
  • SQL Server support Query Notifications
  • Oracle support Continuous Query Notifications.
  • MySQL supports replication streams, but they're not the same as update notification: they cannot be set up and tear down dynamically for a client and they do not work well for monitoring individual rows a particular application is interested in.
For a disconnected client interested in data sync, all vendors support some sort of replication.


Taobao Single's Days



https://mp.weixin.qq.com/s/om0-CFMHWHk5t-wYPVtSQg
一个重要事情是怎样减少这种花费很多人力方式,能不能搞成自动化,或者通过架构优化来解决性能以及错误等问题。用技术手段而不是堆人力方式。

复盘存储读取,读取本身有比较多监控,遇到问题有几类:
1、通用数据读取热点,数据热点会导致redis集群性能下降,这种需要定时去读取来解决。

2、这次备战时遇到新问题,刷子带来热点问题,可以采取缓存来解决。就是服务内存缓存来挡住刷子用户,避免redis产生热点。

3、连接数问题,连接过多会导致连接取不到,a、采取机房分离策略,廊房服务读廊房集群,马驹桥读马驹桥机房,减少连接。b、集群规模减小,数据存的少了,读它的就少了,读的少了,redis客户端客户端减少从而减少连接。c、连接问题通过业务拆分方式解决,单个业务单个集群,集群规模变小,业务之间影响变小,共享集群一个业务导致集群不稳定,其他集群也不稳定。c、小集群业务集群问题不大,还有偏好这种通用数据,读的业务很多,就需要一主多从来解决。

复盘遇到问题,对于存储读取前边做了很多工作,读取方面遇到问题减少了。最近又遇到存储增长问题,有同学设计了一套监控体系,对存储每个任务进行监控,监控后可以设置监控指标,达到指标后进行报警。挺好一种设计,根读取类似都是采取定量方式,清晰定位存储量问题,后续扩容还是构建新的集群就是水到渠成的事。

电商系统稳定关系着核心用户体验,保证稳定方式需要减少外部依赖,所有外部资源都可能会导致问题,减少依赖就能减少出问题的风险。另一条重要原则是后续备案,很重要一件事是要有备选方案出了问题能够有备选供选择。

降级、限流、限速、熔断等都是一种备案。
1、降级是通过降掉非核心流程,保证核心流程稳定高效。或者解决0点流量来临时,存储不稳定,网络不稳定后的处理方式,直接将逻辑降级,不使用。

2、限流,单个服务单个容器能够处理的量是有限的,单机压出上限后,增加限流google guava包有相应方法,直接用即可。

3、熔断,服务直接返回状态给客户端,客户端不再请求服务,从而保护服务,此时服务不是全的,但是不影响用户体验。

再有就是服务出现问题时,要第一时间降级操作,不要想着去解决问题,因为解决问题会耽误时间,影响用户体验,需要后续去定位问题,这是很重要一点,教过学费的。

架构设计,监控是一种重要架构哲学,对于系统优化一个前提,监控本身也能对整个系统所处状态进行呈现,作为我们的决策依据。

花费人力去盯的地方,都应该想一下怎样通过架构以及设计来解决,更多自动化去做,减少人力,用技术方式解决问题,这应该是我们应当追求的。

备案也是一种重要设计哲学,做到有备无患,不能只能看着系统崩溃而束手无策。事情一定要进行总结,才能在这件事中获得更多信息,不然更多是经过,事情要想办法去把它做好,是将来做任何事情一种很重要方式、方法。

解决技术问题,应该通过好的策略好的架构来实现。解决问题过程中我们获得技术提升。

Monday, November 12, 2018

Spring Cloud



https://mp.weixin.qq.com/s/mOk0KuEWQUiugyRA3-FXwg
那么问题来了,Feign是如何做到这么神奇的呢?很简单,Feign的一个关键机制就是使用了动态代理。咱们一起来看看下面的图,结合图来分析:
  • 首先,如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理
  • 接着你要是调用那个接口,本质就是会调用 Feign创建的动态代理,这是核心中的核心
  • Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址
  • 最后针对这个地址,发起请求、解析响应
说完了Feign,还没完。现在新的问题又来了,如果人家库存服务部署在了5台机器上,如下所示:
  • 192.168.169:9000
  • 192.168.170:9000
  • 192.168.171:9000
  • 192.168.172:9000
  • 192.168.173:9000

这下麻烦了!人家Feign怎么知道该请求哪台机器呢?
  • 这时Spring Cloud Ribbon就派上用场了。Ribbon就是专门解决这个问题的。它的作用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把请求分发到各个机器上
  • Ribbon的负载均衡默认使用的最经典的Round Robin轮询算法。这是啥?简单来说,就是如果订单服务对库存服务发起10次请求,那就先让你请求第1台机器、然后是第2台机器、第3台机器、第4台机器、第5台机器,接着再来—个循环,第1台机器、第2台机器。。。以此类推。

 此外,Ribbon是和Feign以及Eureka紧密协作,完成工作的,具体如下:
  • 首先Ribbon会从 Eureka Client里获取到对应的服务注册表,也就知道了所有的服务都部署在了哪些机器上,在监听哪些端口号。
  • 然后Ribbon就可以使用默认的Round Robin算法,从中选择一台机器
  • Feign就会针对这台机器,构造并发起请求。
五、Spring Cloud核心组件:Hystrix
在微服务架构里,一个系统会有很多的服务。以本文的业务场景为例:订单服务在一个业务流程里需要调用三个服务。现在假设订单服务自己最多只有100个线程可以处理请求,然后呢,积分服务不幸的挂了,每次订单服务调用积分服务的时候,都会卡住几秒钟,然后抛出—个超时异常。

咱们一起来分析一下,这样会导致什么问题?
  1. 如果系统处于高并发的场景下,大量请求涌过来的时候,订单服务的100个线程都会卡在请求积分服务这块。导致订单服务没有一个线程可以处理请求
  2. 然后就会导致别人请求订单服务的时候,发现订单服务也挂了,不响应任何请求了
如上图,这么多服务互相调用,要是不做任何保护的话,某一个服务挂了,就会引起连锁反应,导致别的服务也挂。比如积分服务挂了,会导致订单服务的线程全部卡在请求积分服务这里,没有一个线程可以工作,瞬间导致订单服务也挂了,别人请求订单服务全部会卡住,无法响应。


但是我们思考一下,就算积分服务挂了,订单服务也可以不用挂啊!为什么?
  • 我们结合业务来看:支付订单的时候,只要把库存扣减了,然后通知仓库发货就OK了
  • 如果积分服务挂了,大不了等他恢复之后,慢慢人肉手工恢复数据!为啥一定要因为一个积分服务挂了,就直接导致订单服务也挂了呢?不可以接受!

这时就轮到Hystrix闪亮登场了。Hystrix是隔离、熔断以及降级的一个框架。啥意思呢?说白了,Hystrix会搞很多个小小的线程池,比如订单服务请求库存服务是一个线程池,请求仓储服务是一个线程池,请求积分服务是一个线程池。每个线程池里的线程就仅仅用于请求那个服务。


打个比方:现在很不幸,积分服务挂了,会咋样?
当然会导致订单服务里的那个用来调用积分服务的线程都卡死不能工作了啊!但是由于订单服务调用库存服务、仓储服务的这两个线程池都是正常工作的,所以这两个服务不会受到任何影响。


这个时候如果别人请求订单服务,订单服务还是可以正常调用库存服务扣减库存,调用仓储服务通知发货。只不过调用积分服务的时候,每次都会报错。但是如果积分服务都挂了,每次调用都要去卡住几秒钟干啥呢?有意义吗?当然没有!所以我们直接对积分服务熔断不就得了,比如在5分钟内请求积分服务直接就返回了,不要去走网络请求卡住几秒钟,这个过程,就是所谓的熔断!


那人家又说,兄弟,积分服务挂了你就熔断,好歹你干点儿什么啊!别啥都不干就直接返回啊?没问题,咱们就来个降级:每次调用积分服务,你就在数据库里记录一条消息,说给某某用户增加了多少积分,因为积分服务挂了,导致没增加成功!这样等积分服务恢复了,你可以根据这些记录手工加一下积分。这个过程,就是所谓的降级。

六、Spring Cloud核心组件:Zuul

说完了Hystrix,接着给大家说说最后一个组件:Zuul,也就是微服务网关。这个组件是负责网络路由的。不懂网络路由?行,那我给你说说,如果没有Zuul的日常工作会怎样?


假设你后台部署了几百个服务,现在有个前端兄弟,人家请求是直接从浏览器那儿发过来的。打个比方:人家要请求一下库存服务,你难道还让人家记着这服务的名字叫做inventory-service?部署在5台机器上?就算人家肯记住这一个,你后台可有几百个服务的名称和地址呢?难不成人家请求一个,就得记住一个?你要这样玩儿,那真是友谊的小船,说翻就翻!


上面这种情况,压根儿是不现实的。所以一般微服务架构中都必然会设计一个网关在里面,像android、iospc前端、微信小程序、H5等等,不用去关心后端有几百个服务,就知道有一个网关,所有请求都往网关走,网关会根据请求中的一些特征,将请求转发给后端的各个服务。


而且有一个网关之后,还有很多好处,比如可以做统一的降级、限流、认证授权、安全,等等。
  • Eureka:各个服务启动时,Eureka Client都会将服务注册到Eureka Server,并且Eureka Client还可以反过来从Eureka Server拉取注册表,从而知道其他服务在哪里
  • Ribbon:服务间发起请求的时候,基于Ribbon做负载均衡,从一个服务的多台机器中选择一台
  • Feign:基于Feign的动态代理机制,根据注解和选择的机器,拼接请求URL地址,发起请求
  • Hystrix:发起请求是通过Hystrix的线程池来走的,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题
  • Zuul:如果前端、移动端要调用后端系统,统一从Zuul网关进入,由Zuul网关转发请求给对应的服务

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts