日志监控grafna的两种方案

  • telegraf+influxdb+Grafana比较轻量,出图快,社区版不支持集群
  • Zabbix-相对于上一种方案比较重量,出图慢

缓存一致性

CPU的读写单元正常情况下不能直接访问内存,因为并没有管脚直接连接到内存。相反,CPU和一级缓存通讯,一级和二级,二级和三级...n级才能和内存通讯。

如只处理Read,事情会变很简单,因为

所有级别的缓存遵循:在任意时刻,任意级别缓存中的内容等同于它对应的内存中的内容.

如果考虑写操作

直写(遵循定律)

我们透过本级缓存,直接将数据写到下一级缓存,如当前对应段已被这级缓存了,则更新/丢弃。

回写

缓存不会立即吧写操作传递,仅把本级已修改段标记为脏段。脏段会触发回写(写入下一级), 脏段洗净。总结: 当一个脏段被丢弃时,总会先回写。
回写定律: 所有脏段回写后, 任意级别缓存中的内容等同于它对应的内存中的内容.

一致性协议

当单核情况时,没毛病。
如果有多个核, 且拥有自己的缓存(有些CPU共用一块缓存[太慢了]), 且为了解决回写带来的问题, 所以产生了MESI及其衍生协议.

  • Modified 已修改缓存段,当某个核心持有了M状态的缓存段, 其他拥有或等待拥有其内存段的其他核心中的拷贝会马上失效(I)
  • Exclusive 独占缓存段,与主存一致拷贝, 当某个核心持有了E状态的缓存段,其他拥有有其内存段的其他核心中的拷贝会马上失效(I), 且其他核心无法同时持有它
  • Shared 共享缓存段, 与主存一致拷贝, 此状态下的缓存段是只读的, 可被多个核心持有
  • Invalid 失效缓存段, 属于脏段,已不在缓存中/被其他核心M/E, 将会被忽略(相当于从来没被加载)

MESI 定律:在所有的脏缓存段(M 状态)被回写后,任意缓存级别的所有缓存段中的内容,和它们对应的内存中的内容一致。此外,在任意时刻,当某个位置的内存被一个处理器加载入独占缓存段时(E 状态),那它就不会再出现在其他任何处理器的缓存中。

有很多文章说“CPU乱序执行和预测执行”会导致最终写入到内存的数据不符合预期,事实是此结果会被丢弃。
参考:
CPU乱序执行和预测执行导致的安全问题
Wikipedia: Out-of-order execution

Concurrency

CountDownLatch

    CountDownLatch countdownlatch = new CountDownLatch(1); // The difinition count is 1
    System.out.println("Count: " + countdownlatch.getCount()); // 1

    new Thread(() -> {
        try {
            countdownlatch.await(); // Current thread enter await, until count reduced to 0
            System.out.println("Count: " + countdownlatch.getCount()); // 0
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();

    Thread.sleep(1000);
    System.out.println("Count down");
    countdownlatch.countDown(); // down 1

CyclicBarrier

    public class CyclicBarrierExample {

        private static LongAdder count = new LongAdder();
        private static ExecutorService executorService = Executors.newFixedThreadPool(5);
        private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> System.out.println(count.longValue()));

        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                executorService.execute(CyclicBarrierExample::add);
            }
            executorService.shutdown();
        }

        private static void add() {
            try {
                count.increment();
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

Semaphore

    Semaphore semaphore = new Semaphore(5);
    for (int i = 0; i < 5; i++) {
        new Thread(() -> {
            try {
                semaphore.acquire(); // Get a semaphore
                semaphore.release(); // Release a semaphore
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
       Thread.sleep(1000);
    System.out.println("Available semaphore: " + semaphore.availablePermits()); // 5
    Semaphore semaphore = new Semaphore(5);
    for (int i = 0; i < 5; i++) {
        new Thread(() -> {
            try {
                semaphore.acquire();
                //semaphore.release(); // Not release
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
    Thread.sleep(1000);
    System.out.println("Available semaphore: " + semaphore.availablePermits()); // 0
    Semaphore semaphore = new Semaphore(5);
    for (int i = 0; i < 5; i++) {
        new Thread(() -> {
            try {
                semaphore.acquire();
                //semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
    Thread.sleep(1000);
    System.out.println("Available semaphore: " + semaphore.availablePermits()); // 0
    semaphore.acquire(); // Because available semaphore is 0, threa enters await status, until available gt 0
    System.out.println("END"); // Always not output END

Atomic

AtomicLong and LongAdder

Jdk8 update LongAdder and DoubleAdder

Under low update contention, the two classes have similar characteristics. But under
high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption.

Recommend use 'LongAdder' and 'DoubleAdder',
But may not be safe of reading(update value when reading), AtomicLong is safer, its principle is CAS(compareAndSwap)

AtomicXX

@Slf4j
@ThreadSafe
    public class AtomicTest {

        private final static int threadTotal = 200;
        private final static int clientTotal = 5000;
        // private static AtomicLong count = new AtomicLong(0);
        private static LongAdder count = new LongAdder(); //Initial value is 0

        public static void main(String[] args) throws Exception {
            ExecutorService executor = Executors.newCachedThreadPool();
            Semaphore semaphore = new Semaphore(threadTotal);
            CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
            log.info("CountdownLatch count: {}", countDownLatch.getCount());

            new Thread(() -> {
                try {
                    countDownLatch.await();
                    executor.shutdown();
                    log.info("CountdownLatch count: {}", countDownLatch.getCount());
                    log.info("count: {}", count.longValue());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }).start();

            Thread.sleep(1000);
            for (int i = 0; i < clientTotal; i++) {
                executor.execute(() -> {
                    try {
                        semaphore.acquire();
                        add();
                        semaphore.release();
                        countDownLatch.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
        }

        private static void add() {
            count.increment();
        }
    }

AtomicReference

An object reference that may be updated atomically.

    public class AtomicReferenceTest {

        @Data
        private static class User {
            private String name;
        }

        public static void main(String[] args) {
            AtomicReference<User> longAtomicReference = new AtomicReference<>();
            User oldUser = new User();
            oldUser.setName("old");
            longAtomicReference.set(oldUser);

            User userBak = oldUser; // Copy user addr
            oldUser = new User();

            boolean b = longAtomicReference.compareAndSet(oldUser, userBak); // Check addr value, if equals, update it
            System.out.println(b);
        }
    }

AtomicReferenceFieldUpdater

Modify object field

    public class AtomicReferenceFieldUpdaterTest {

        @Data
        private static class User {
            volatile String name;
        }

        public static void main(String[] args) {
            AtomicReferenceFieldUpdater<User, String> atomicReferenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(User.class, String.class, "name");
            User user = new User();
            user.setName("Wars");

            atomicReferenceFieldUpdater.compareAndSet(user, user.getName(), "Cat");
            System.out.println(user.getName());
        }
    }

AtomicStampedReference

AtomicStampedReference vs. AtomicReference added one version number param, fix ABA bug

    public class AtomicStampedReferenceTest {

        private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(0, 0);

        public static void main(String[] args) {
            atomicStampedReference.compareAndSet(0, 1, 0, 1);
        }
    }

AtomicLongArray

AtomicLongArray through the index operation array

    public class AtomicLongArrayTest {

        private static AtomicLongArray atomicLongArray = new AtomicLongArray(new long[]{1L, 2L, 3L});

        public static void main(String[] args) {
            atomicLongArray.incrementAndGet(0); // index
        }
    }

Synchronized

  • Code scope

    • If synchronized(this), not unique: The current instance is valid
    • If synchronized(A.class), unique: The all instance is valid
  • Function

    • equals synchronized(this){} this function content
    • The current instance is valid
  • Static function

    • equals synchronized(This.class){} this function content
    • The all instance is valid
  • Class

    • equals synchronized(This.class){} all function content of this class
    • The all instance is valid

volatile

Guaranteed single thread, sequential execution of reads and writes
1) Wrong usage

    @NotThreadSafe
    public class VolatileTest {

        private static final int MAX_THREAD = 50;
        private static final int EXECUTE_COUNT = 5000;
        private static volatile int count = 0;

        public static void main(String[] args) {
            CountDownLatch countDownLatch = new CountDownLatch(EXECUTE_COUNT);
            // Executed out
            new Thread(() -> {
                try {
                    countDownLatch.await();
                    System.out.println("count: " + count);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

            // Executor
            ExecutorService executor = Executors.newCachedThreadPool();
            Semaphore semaphore = new Semaphore(MAX_THREAD);
            for (int i = 0; i < EXECUTE_COUNT; i++) {
                executor.execute(() -> {
                    try {
                        semaphore.acquire();
                        count++;
                        semaphore.release();
                        countDownLatch.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
        }
    }

2) Recommended usage

    public class VolatileTest2 {

        private static volatile boolean semaphore = false;

        public static void main(String[] args) throws InterruptedException {
            new Thread(() -> {
                try {
                    while (!semaphore) Thread.sleep(1000);
                    System.out.println("Finish");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();


            Thread.sleep(10000);
            semaphore = true;
        }
    }

Singleton publish

  1. Dual if lazy mode
    @ThreadSafe
    public class A_Singleton {

        private volatile static A_Singleton instance;

        private A_Singleton() {
        }

        public static A_Singleton getInstance() {
            if (null == instance)
                synchronized (A_Singleton.class) {
                    instance = new A_Singleton(); // If no volatile, it may lead to Out-of-order execution initialization
                }

            return instance;
        }
    }
  1. Static scope Hungry mode
    @ThreadSafe
    public class B {

        private static B instance;

        static {
            instance = new B();
        }

        private B() {
        }

        public static B getInstance() {
            return instance;
        }
    }
  1. Enum mode
    enum E {
        INSTANCE;

        private C_EnumMode instance;

        E() {
            instance = new C_EnumMode();
        }

        public C_EnumMode getInstance() {
            return instance;
        }
    }