In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >
Share
Shulou(Shulou.com)06/01 Report--
Overview
At present, almost many large websites and applications are distributed, and the problem of data consistency in distributed scenarios has always been an important topic. Distributed CAP theory tells us that "no distributed system can satisfy Consistency, Availability and Partition tolerance at the same time, but only two at the same time." Therefore, many systems have to make a choice between these three at the beginning of their design. In the vast majority of scenarios in the Internet field, strong consistency needs to be sacrificed for high availability of the system, and systems often only need to ensure "ultimate consistency", as long as the final time is within the range acceptable to the user.
In many scenarios, in order to ensure the ultimate consistency of data, we need a lot of technical solutions to support, such as distributed transactions, distributed locks and so on.
Choose Redis to realize distributed lock reason
Redis has high performance.
The Redis command supports this well and is easy to implement.
The installation of Redis will not be introduced here.
Introduction to using commands
SETNX
SETNX key val
If and only if key does not exist, set a string whose key is val and returns 1; if key exists, it does nothing and returns 0.
Expire
Expire key timeout
Set a timeout for key in second, after which the lock will be automatically released to avoid deadlock.
Delete
Delete key
Delete key
These three commands are mainly used when using Redis to implement distributed locks.
Realize
Jedis is used to connect to the Redis.
Realization thought
When acquiring a lock, use setnx to add a lock, and use the expire command to add a timeout for the lock, after which the lock is automatically released. The value of the lock is a randomly generated UUID, which can be judged when the lock is released.
When acquiring the lock, you also set a timeout for the acquisition, and if it exceeds this time, the acquisition lock is discarded.
When releasing the lock, the UUID determines whether it is the lock or not, and if it is the lock, delete is executed to release the lock.
The core code of the distributed lock is as follows:
Import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.Transaction;import redis.clients.jedis.exceptions.JedisException;import java.util.List;import java.util.UUID;/** * Created by liuyang on 2017-4-20. * / public class DistributedLock {private final JedisPool jedisPool; public DistributedLock (JedisPool jedisPool) {this.jedisPool = jedisPool } / * * Lock * @ param locaName lock key * @ param acquireTimeout acquires timeout * @ param timeout lock timeout * @ return lock ID * / public String lockWithTimeout (String locaName, long acquireTimeout, long timeout) {Jedis conn = null; String retIdentifier = null; try {/ / get connection conn = jedisPool.getResource (); / / randomly generate a value String identifier = UUID.randomUUID (). ToString () / / lock name, that is, the key value String lockKey = "lock:" + locaName; / / timeout. After locking, the lock is automatically released int lockExpire = (int) (timeout / 1000); / / the timeout of the lock is acquired. If the timeout is exceeded, the lock long end = System.currentTimeMillis () + acquireTimeout; while (System.currentTimeMillis ()) is abandoned.
< end) { if (conn.setnx(lockKey, identifier) == 1) { conn.expire(lockKey, lockExpire); // 返回value值,用于释放锁时间确认 retIdentifier = identifier; return retIdentifier; } // 返回-1代表key没有设置超时时间,为key设置一个超时时间 if (conn.ttl(lockKey) == -1) { conn.expire(lockKey, lockExpire); } try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } catch (JedisException e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } return retIdentifier; } /** * 释放锁 * @param lockName 锁的key * @param identifier 释放锁的标识 * @return */ public boolean releaseLock(String lockName, String identifier) { Jedis conn = null; String lockKey = "lock:" + lockName; boolean retFlag = false; try { conn = jedisPool.getResource(); while (true) { // 监视lock,准备开始事务 conn.watch(lockKey); // 通过前面返回的value值判断是不是该锁,若是该锁,则删除,释放锁 if (identifier.equals(conn.get(lockKey))) { Transaction transaction = conn.multi(); transaction.del(lockKey); List results = transaction.exec(); if (results == null) { continue; } retFlag = true; } conn.unwatch(); break; } } catch (JedisException e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } return retFlag; }} 测试 下面就用一个简单的例子测试刚才实现的分布式锁。 例子中使用50个线程模拟秒杀一个商品,使用--运算符来实现商品减少,从结果有序性就可以看出是否为加锁状态。 模拟秒杀服务,在其中配置了jedis线程池,在初始化的时候传给分布式锁,供其使用。 import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;/** * Created by liuyang on 2017/4/20. */public class Service { private static JedisPool pool = null; static { JedisPoolConfig config = new JedisPoolConfig(); // 设置最大连接数 config.setMaxTotal(200); // 设置最大空闲数 config.setMaxIdle(8); // 设置最大等待时间 config.setMaxWaitMillis(1000 * 100); // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的 config.setTestOnBorrow(true); pool = new JedisPool(config, "127.0.0.1", 6379, 3000); } DistributedLock lock = new DistributedLock(pool); int n = 500; public void seckill() { // 返回锁的value值,供释放锁时候进行判断 String indentifier = lock.lockWithTimeout("resource", 5000, 1000); System.out.println(Thread.currentThread().getName() + "获得了锁"); System.out.println(--n); lock.releaseLock("resource", indentifier); }}// 模拟线程进行秒杀服务public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { this.service = service; } @Override public void run() { service.seckill(); }}public class Test { public static void main(String[] args) { Service service = new Service(); for (int i = 0; i < 50; i++) { ThreadA threadA = new ThreadA(service); threadA.start(); } }} 结果如下,结果为有序的。If you comment out the part that uses the lock
Public void seckill () {/ / returns the value of the lock for judging / / String indentifier = lock.lockWithTimeout ("resource", 5000, 1000); System.out.println (Thread.currentThread (). GetName () + "acquired lock"); System.out.println (--n); / / lock.releaseLock ("resource", indentifier);}
As can be seen from the results, some of them are done asynchronously.
In a distributed environment, it is sometimes important to lock resources, such as snapping up a resource, which can be well controlled by using distributed locks.
Of course, in the specific use, we also need to consider many factors, such as the selection of timeout time, the selection of acquisition lock time has a great impact on the concurrency, the above implementation of the distributed lock is only a simple implementation, mainly an idea.
Next time I will use zookeeper to implement distributed locks. The reliability of using zookeeper is greater than that of distributed locks implemented using redis, but redis has better performance.
The above code can be viewed in my GitHub.
The above is the whole content of this article, I hope it will be helpful to your study, and I also hope that you will support it.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.