Inhaltsverzeichnis
1. 单机数据一致性
2. 分布式数据一致性
3. Redis实现分布式锁
3.1 方式一
3.2 方式二(改进方式一)
3.3 方式三(改进方式二)
1. Datenkonsistenz auf einer Maschine
2. Verteilte Datenkonsistenz
3. Redis implementiert verteilte Sperren
3.1 Methode 1
3.2 Methode 2 (Verbesserungsmethode 1)
3.3 Methode drei (verbesserte Methode zwei)
3.4 方式四(改进方式三)
3.5 方式五(改进方式四)
Heim Datenbank Redis Zusammenfassung von fünf Möglichkeiten zur Implementierung verteilter Sperren in Redis

Zusammenfassung von fünf Möglichkeiten zur Implementierung verteilter Sperren in Redis

Sep 14, 2022 pm 05:56 PM
redis

Empfohlenes Lernen: Redis-Video-Tutorial

Wenn wir in einer einzelnen Anwendung die gemeinsam genutzten Daten nicht sperren, treten normalerweise Datenkonsistenzprobleme auf. Unsere Lösung besteht darin, sie zu sperren.

In der verteilten Architektur werden wir auch auf Probleme beim Datenaustausch stoßen. In diesem Artikel wird Redis verwendet, um das Datenkonsistenzproblem in der verteilten Architektur zu lösen. Redis来解决分布式架构中的数据一致性问题。

1. 单机数据一致性

单机数据一致性架构如下图所示:多个可客户访问同一个服务器,连接同一个数据库。

场景描述:客户端模拟购买商品过程,在Redis中设定库存总数剩100,多个客户端同时并发购买。

@RestController
public class IndexController1 {

    @Autowired
    StringRedisTemplate template;

    @RequestMapping("/buy1")
    public String index(){
        // Redis中存有goods:001号商品,数量为100
        String result = template.opsForValue().get("goods:001");
        // 获取到剩余商品数
        int total = result == null ? 0 : Integer.parseInt(result);
        if( total > 0 ){
            // 剩余商品数大于0 ,则进行扣减
            int realTotal = total -1;
            // 将商品数回写数据库
            template.opsForValue().set("goods:001",String.valueOf(realTotal));
            System.out.println("购买商品成功,库存还剩:"+realTotal +"件, 服务端口为8001");
            return "购买商品成功,库存还剩:"+realTotal +"件, 服务端口为8001";
        }else{
            System.out.println("购买商品失败,服务端口为8001");
        }
        return "购买商品失败,服务端口为8001";
    }
}
Nach dem Login kopieren

使用Jmeter模拟高并发场景,测试结果如下:

测试结果出现多个用户购买同一商品,发生了数据不一致问题!

解决办法:单体应用的情况下,对并发的操作进行加锁操作,保证对数据的操作具有原子性

  • synchronized
  • ReentrantLock
@RestController
public class IndexController2 {
// 使用ReentrantLock锁解决单体应用的并发问题
Lock lock = new ReentrantLock();

@Autowired
StringRedisTemplate template;

@RequestMapping("/buy2")
public String index() {

    lock.lock();
    try {
        String result = template.opsForValue().get("goods:001");
        int total = result == null ? 0 : Integer.parseInt(result);
        if (total > 0) {
            int realTotal = total - 1;
            template.opsForValue().set("goods:001", String.valueOf(realTotal));
            System.out.println("购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001");
            return "购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001";
        } else {
            System.out.println("购买商品失败,服务端口为8001");
        }
    } catch (Exception e) {
        lock.unlock();
    } finally {
        lock.unlock();
    }
    return "购买商品失败,服务端口为8001";
}
}
Nach dem Login kopieren

2. 分布式数据一致性

上面解决了单体应用的数据一致性问题,但如果是分布式架构部署呢,架构如下:

提供两个服务,端口分别为80018002,连接同一个Redis服务,在服务前面有一台Nginx作为负载均衡

两台服务代码相同,只是端口不同

80018002两个服务启动,每个服务依然用ReentrantLock加锁,用Jmeter做并发测试,发现会出现数据一致性问题!

3. Redis实现分布式锁

3.1 方式一

取消单机锁,下面使用redisset命令来实现分布式加锁

SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]

  • EX seconds 设置指定的到期时间(以秒为单位)
  • PX milliseconds 设置指定的到期时间(以毫秒为单位)
  • NX 仅在键不存在时设置键
  • XX 只有在键已存在时才设置
@RestController
public class IndexController4 {

    // Redis分布式锁的key
    public static final String REDIS_LOCK = "good_lock";

    @Autowired
    StringRedisTemplate template;

    @RequestMapping("/buy4")
    public String index(){

        // 每个人进来先要进行加锁,key值为"good_lock",value随机生成
        String value = UUID.randomUUID().toString().replace("-","");
        try{
            // 加锁
            Boolean flag = template.opsForValue().setIfAbsent(REDIS_LOCK, value);
            // 加锁失败
            if(!flag){
                return "抢锁失败!";
            }
            System.out.println( value+ " 抢锁成功");
            String result = template.opsForValue().get("goods:001");
            int total = result == null ? 0 : Integer.parseInt(result);
            if (total > 0) {
                int realTotal = total - 1;
                template.opsForValue().set("goods:001", String.valueOf(realTotal));
                // 如果在抢到所之后,删除锁之前,发生了异常,锁就无法被释放,
                // 释放锁操作不能在此操作,要在finally处理
				// template.delete(REDIS_LOCK);
                System.out.println("购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001");
                return "购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001";
            } else {
                System.out.println("购买商品失败,服务端口为8001");
            }
            return "购买商品失败,服务端口为8001";
        }finally {
            // 释放锁
            template.delete(REDIS_LOCK);
        }
    }
}
Nach dem Login kopieren

上面的代码,可以解决分布式架构中数据一致性问题。但再仔细想想,还是会有问题,下面进行改进。

3.2 方式二(改进方式一)

在上面的代码中,如果程序在运行期间,部署了微服务jar包的机器突然挂了,代码层面根本就没有走到finally代码块,也就是说在宕机前,锁并没有被删除掉,这样的话,就没办法保证解锁

所以,这里需要对这个key加一个过期时间,Redis中设置过期时间有两种方法:

  • template.expire(REDIS_LOCK,10, TimeUnit.SECONDS)
  • template.opsForValue().setIfAbsent(REDIS_LOCK, value,10L,TimeUnit.SECONDS)

第一种方法需要单独的一行代码,且并没有与加锁放在同一步操作,所以不具备原子性,也会出问题

第二种方法在加锁的同时就进行了设置过期时间,所有没有问题,这里采用这种方式

调整下代码,在加锁的同时,设置过期时间:

// 为key加一个过期时间,其余代码不变
Boolean flag = template.opsForValue().setIfAbsent(REDIS_LOCK,value,10L,TimeUnit.SECONDS);
Nach dem Login kopieren

这种方式解决了因服务突然宕机而无法释放锁的问题。但再仔细想想,还是会有问题,下面进行改进。

3.3 方式三(改进方式二)

方式二设置了key的过期时间,解决了key

1. Datenkonsistenz auf einer Maschine

Die Architektur der Datenkonsistenz auf einer Maschine ist in der folgenden Abbildung dargestellt: Mehrere Clients können auf denselben Server zugreifen und eine Verbindung zu derselben Datenbank herstellen. 🎜

🎜🎜Szenariobeschreibung: Der Kunde simuliert den Prozess des Wareneinkaufs und setzt den Gesamtbestand in Redis auf 100 Stück. Mehrere Kunden kaufen gleichzeitig. 🎜

🎜

@RestController
public class IndexController6 {

    public static final String REDIS_LOCK = "good_lock";

    @Autowired
    StringRedisTemplate template;

    @RequestMapping("/buy6")
    public String index(){

        // 每个人进来先要进行加锁,key值为"good_lock"
        String value = UUID.randomUUID().toString().replace("-","");
        try{
            // 为key加一个过期时间
            Boolean flag = template.opsForValue().setIfAbsent(REDIS_LOCK, value,10L,TimeUnit.SECONDS);

            // 加锁失败
            if(!flag){
                return "抢锁失败!";
            }
            System.out.println( value+ " 抢锁成功");
            String result = template.opsForValue().get("goods:001");
            int total = result == null ? 0 : Integer.parseInt(result);
            if (total > 0) {
                // 如果在此处需要调用其他微服务,处理时间较长。。。
                int realTotal = total - 1;
                template.opsForValue().set("goods:001", String.valueOf(realTotal));
                System.out.println("购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001");
                return "购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001";
            } else {
                System.out.println("购买商品失败,服务端口为8001");
            }
            return "购买商品失败,服务端口为8001";
        }finally {
            // 谁加的锁,谁才能删除!!!!
            if(template.opsForValue().get(REDIS_LOCK).equals(value)){
                template.delete(REDIS_LOCK);
            }
        }
    }
}
Nach dem Login kopieren
Nach dem Login kopieren
🎜Verwenden Sie Jmeter, um Szenarien mit hoher Parallelität zu simulieren. Die Testergebnisse lauten wie folgt: 🎜

🎜🎜Die Testergebnisse zeigten, dass mehrere Benutzer dasselbe Produkt gekauft haben und es zu Dateninkonsistenzen kam! 🎜🎜Lösung: Sperren Sie im Falle einer einzelnen Anwendung gleichzeitige Vorgänge, um sicherzustellen, dass Datenvorgänge atomar sind. 🎜

  • synchronisiert
  • ReentrantLock</ Code></li></ul><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>@RestController public class IndexController7 { public static final String REDIS_LOCK = &quot;good_lock&quot;; @Autowired StringRedisTemplate template; @RequestMapping(&quot;/buy7&quot;) public String index(){ // 每个人进来先要进行加锁,key值为&quot;good_lock&quot; String value = UUID.randomUUID().toString().replace(&quot;-&quot;,&quot;&quot;); try{ // 为key加一个过期时间 Boolean flag = template.opsForValue().setIfAbsent(REDIS_LOCK, value,10L,TimeUnit.SECONDS); // 加锁失败 if(!flag){ return &quot;抢锁失败!&quot;; } System.out.println( value+ &quot; 抢锁成功&quot;); String result = template.opsForValue().get(&quot;goods:001&quot;); int total = result == null ? 0 : Integer.parseInt(result); if (total &gt; 0) { // 如果在此处需要调用其他微服务,处理时间较长。。。 int realTotal = total - 1; template.opsForValue().set(&quot;goods:001&quot;, String.valueOf(realTotal)); System.out.println(&quot;购买商品成功,库存还剩:&quot; + realTotal + &quot;件, 服务端口为8001&quot;); return &quot;购买商品成功,库存还剩:&quot; + realTotal + &quot;件, 服务端口为8001&quot;; } else { System.out.println(&quot;购买商品失败,服务端口为8001&quot;); } return &quot;购买商品失败,服务端口为8001&quot;; }finally { // 谁加的锁,谁才能删除,使用Lua脚本,进行锁的删除 Jedis jedis = null; try{ jedis = RedisUtils.getJedis(); String script = &quot;if redis.call(&amp;#39;get&amp;#39;,KEYS[1]) == ARGV[1] &quot; + &quot;then &quot; + &quot;return redis.call(&amp;#39;del&amp;#39;,KEYS[1]) &quot; + &quot;else &quot; + &quot; return 0 &quot; + &quot;end&quot;; Object eval = jedis.eval(script, Collections.singletonList(REDIS_LOCK), Collections.singletonList(value)); if(&quot;1&quot;.equals(eval.toString())){ System.out.println(&quot;-----del redis lock ok....&quot;); }else{ System.out.println(&quot;-----del redis lock error ....&quot;); } }catch (Exception e){ }finally { if(null != jedis){ jedis.close(); } } } } }</pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div><p style="text-align:center"><img alt="" src="https://img.php.cn/upload /article/000/000/ 067/ecdd93debcd01892658ec6730e0ca4e4-3.png"/>🎜<h2 id="Verteilte-Datenkonsistenz">2. Verteilte Datenkonsistenz</h2>🎜Das Obige löst das Datenkonsistenzproblem einer einzelnen Anwendung, aber wenn es verteilt ist. Was die Architekturbereitstellung betrifft, ist die Architektur wie folgt folgt: 🎜🎜 Bietet zwei Dienste, die Ports sind <code>8001, 8002, verbunden mit demselben Redis-Dienst, im Dienst gibt es einen < code>Nginx vorne als Load Balancer🎜

    🎜🎜Die beiden Dienstcodes sind gleich, aber die Ports sind unterschiedlich🎜🎜Starten Sie die beiden Dienste 8001 und 8002</code >. Jeder Dienst ist weiterhin mit <code>ReentrantLock gesperrt und Jmeter wird für Parallelitätstests verwendet. Es wurde festgestellt, dass es zu Datenkonsistenzproblemen kommen wird. 🎜

    🎜

    3. Redis implementiert verteilte Sperren

    3.1 Methode 1

    🎜Um die eigenständige Sperre aufzuheben, verwenden Sie den Befehl set von redis< /code> unten So implementieren Sie verteiltes Sperren🎜🎜SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]🎜<ul><li>EX seconds legt die angegebene Ablaufzeit (in Sekunden) fest</li>< li >PX Millisekunden legt die angegebene Ablaufzeit in Millisekunden fest</li><li>NX Legt den Schlüssel nur fest, wenn der Schlüssel nicht existiert</li><li>XX Legt den Schlüssel nur fest, wenn er bereits existiert</li><li > li></ul><div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>@RestController public class IndexController8 { public static final String REDIS_LOCK = &quot;good_lock&quot;; @Autowired StringRedisTemplate template; @Autowired Redisson redisson; @RequestMapping(&quot;/buy8&quot;) public String index(){ RLock lock = redisson.getLock(REDIS_LOCK); lock.lock(); // 每个人进来先要进行加锁,key值为&quot;good_lock&quot; String value = UUID.randomUUID().toString().replace(&quot;-&quot;,&quot;&quot;); try{ String result = template.opsForValue().get(&quot;goods:001&quot;); int total = result == null ? 0 : Integer.parseInt(result); if (total &gt; 0) { // 如果在此处需要调用其他微服务,处理时间较长。。。 int realTotal = total - 1; template.opsForValue().set(&quot;goods:001&quot;, String.valueOf(realTotal)); System.out.println(&quot;购买商品成功,库存还剩:&quot; + realTotal + &quot;件, 服务端口为8001&quot;); return &quot;购买商品成功,库存还剩:&quot; + realTotal + &quot;件, 服务端口为8001&quot;; } else { System.out.println(&quot;购买商品失败,服务端口为8001&quot;); } return &quot;购买商品失败,服务端口为8001&quot;; }finally { if(lock.isLocked() &amp;&amp; lock.isHeldByCurrentThread()){ lock.unlock(); } } } }</pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div>🎜Der obige Code kann das Problem der Datenkonsistenz in verteilten Architekturen lösen. Aber wenn Sie genauer darüber nachdenken, wird es immer noch Probleme geben. Lassen Sie uns unten Verbesserungen vornehmen. 🎜<h3 id="Methode-Verbesserungsmethode">3.2 Methode 2 (Verbesserungsmethode 1)</h3>🎜Wenn im obigen Code der Computer, auf dem das Microservice-<code>jar-Paket bereitgestellt wird, während der Ausführung des Programms plötzlich hängen bleibt, wird der Code angezeigt Level Es hat den Codeblock finally überhaupt nicht erreicht, was bedeutet, dass die Sperre vor dem Herunterfahren nicht gelöscht wurde. In diesem Fall gibt es keine Möglichkeit, die Entsperrung zu garantieren🎜🎜Also, hier brauchen wir Um diesen -Schlüsselzu überprüfen, fügen Sie eine Ablaufzeit hinzu. Es gibt zwei Möglichkeiten, die Ablaufzeit in Redis festzulegen: 🎜
    • template.expire(REDIS_LOCK ,10, TimeUnit.SECONDS)< /code></li><li><code>template.opsForValue().setIfAbsent(REDIS_LOCK, value,10L,TimeUnit.SECONDS)
    🎜Die erste Methode erfordert eine separate A-Codezeile und wird nicht im selben Schritt wie das Sperren platziert, ist also nicht atomar und verursacht Probleme. Die zweite Methode legt die Ablaufzeit gleichzeitig mit dem Sperren fest Dies ist kein Problem. Hier verwenden wir diese Methode: Passen Sie den Code an und legen Sie die Ablaufzeit beim Sperren fest: Aber wenn Sie genauer darüber nachdenken, wird es immer noch Probleme geben. Lassen Sie uns unten Verbesserungen vornehmen. 🎜

    3.3 Methode drei (verbesserte Methode zwei)

    🎜Methode zwei legt die Ablaufzeit von key fest, wodurch das Problem gelöst wird, dass key nicht gelöscht werden kann. aber das Problem Jetzt geht es wieder los 🎜

    上面设置了key的过期时间为10秒,如果业务逻辑比较复杂,需要调用其他微服务,处理时间需要15秒(模拟场

    景,别较真),而当10秒钟过去之后,这个key就过期了,其他请求就又可以设置这个key,此时如果耗时15

    的请求处理完了,回来继续执行程序,就会把别人设置的key给删除了,这是个很严重的问题!

    所以,谁上的锁,谁才能删除

    @RestController
    public class IndexController6 {
    
        public static final String REDIS_LOCK = "good_lock";
    
        @Autowired
        StringRedisTemplate template;
    
        @RequestMapping("/buy6")
        public String index(){
    
            // 每个人进来先要进行加锁,key值为"good_lock"
            String value = UUID.randomUUID().toString().replace("-","");
            try{
                // 为key加一个过期时间
                Boolean flag = template.opsForValue().setIfAbsent(REDIS_LOCK, value,10L,TimeUnit.SECONDS);
    
                // 加锁失败
                if(!flag){
                    return "抢锁失败!";
                }
                System.out.println( value+ " 抢锁成功");
                String result = template.opsForValue().get("goods:001");
                int total = result == null ? 0 : Integer.parseInt(result);
                if (total > 0) {
                    // 如果在此处需要调用其他微服务,处理时间较长。。。
                    int realTotal = total - 1;
                    template.opsForValue().set("goods:001", String.valueOf(realTotal));
                    System.out.println("购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001");
                    return "购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001";
                } else {
                    System.out.println("购买商品失败,服务端口为8001");
                }
                return "购买商品失败,服务端口为8001";
            }finally {
                // 谁加的锁,谁才能删除!!!!
                if(template.opsForValue().get(REDIS_LOCK).equals(value)){
                    template.delete(REDIS_LOCK);
                }
            }
        }
    }
    Nach dem Login kopieren
    Nach dem Login kopieren

    这种方式解决了因服务处理时间太长而释放了别人锁的问题。这样就没问题了吗?

    3.4 方式四(改进方式三)

    在上面方式三下,规定了谁上的锁,谁才能删除,但finally快的判断和del删除操作不是原子操作,并发的时候也会出问题,并发嘛,就是要保证数据的一致性,保证数据的一致性,最好要保证对数据的操作具有原子性。

    Redisset命令介绍中,最后推荐Lua脚本进行锁的删除,地址

    @RestController
    public class IndexController7 {
    
        public static final String REDIS_LOCK = "good_lock";
    
        @Autowired
        StringRedisTemplate template;
    
        @RequestMapping("/buy7")
        public String index(){
    
            // 每个人进来先要进行加锁,key值为"good_lock"
            String value = UUID.randomUUID().toString().replace("-","");
            try{
                // 为key加一个过期时间
                Boolean flag = template.opsForValue().setIfAbsent(REDIS_LOCK, value,10L,TimeUnit.SECONDS);
                // 加锁失败
                if(!flag){
                    return "抢锁失败!";
                }
                System.out.println( value+ " 抢锁成功");
                String result = template.opsForValue().get("goods:001");
                int total = result == null ? 0 : Integer.parseInt(result);
                if (total > 0) {
                    // 如果在此处需要调用其他微服务,处理时间较长。。。
                    int realTotal = total - 1;
                    template.opsForValue().set("goods:001", String.valueOf(realTotal));
                    System.out.println("购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001");
                    return "购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001";
                } else {
                    System.out.println("购买商品失败,服务端口为8001");
                }
                return "购买商品失败,服务端口为8001";
            }finally {
                // 谁加的锁,谁才能删除,使用Lua脚本,进行锁的删除
    
                Jedis jedis = null;
                try{
                    jedis = RedisUtils.getJedis();
    
                    String script = "if redis.call(&#39;get&#39;,KEYS[1]) == ARGV[1] " +
                            "then " +
                            "return redis.call(&#39;del&#39;,KEYS[1]) " +
                            "else " +
                            "   return 0 " +
                            "end";
    
                    Object eval = jedis.eval(script, Collections.singletonList(REDIS_LOCK), Collections.singletonList(value));
                    if("1".equals(eval.toString())){
                        System.out.println("-----del redis lock ok....");
                    }else{
                        System.out.println("-----del redis lock error ....");
                    }
                }catch (Exception e){
    
                }finally {
                    if(null != jedis){
                        jedis.close();
                    }
                }
            }
        }
    }
    Nach dem Login kopieren
    Nach dem Login kopieren

    3.5 方式五(改进方式四)

    在方式四下,规定了谁上的锁,谁才能删除,并且解决了删除操作没有原子性问题。但还没有考虑缓存续命,以及Redis集群部署下,异步复制造成的锁丢失:主节点没来得及把刚刚set进来这条数据给从节点,就挂了。所以直接上RedLockRedisson落地实现。

    @RestController
    public class IndexController8 {
    
        public static final String REDIS_LOCK = "good_lock";
    
        @Autowired
        StringRedisTemplate template;
    
        @Autowired
        Redisson redisson;
    
        @RequestMapping("/buy8")
        public String index(){
    
            RLock lock = redisson.getLock(REDIS_LOCK);
            lock.lock();
    
            // 每个人进来先要进行加锁,key值为"good_lock"
            String value = UUID.randomUUID().toString().replace("-","");
            try{
                String result = template.opsForValue().get("goods:001");
                int total = result == null ? 0 : Integer.parseInt(result);
                if (total > 0) {
                    // 如果在此处需要调用其他微服务,处理时间较长。。。
                    int realTotal = total - 1;
                    template.opsForValue().set("goods:001", String.valueOf(realTotal));
                    System.out.println("购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001");
                    return "购买商品成功,库存还剩:" + realTotal + "件, 服务端口为8001";
                } else {
                    System.out.println("购买商品失败,服务端口为8001");
                }
                return "购买商品失败,服务端口为8001";
            }finally {
                if(lock.isLocked() && lock.isHeldByCurrentThread()){
                    lock.unlock();
                }
            }
        }
    }
    Nach dem Login kopieren
    Nach dem Login kopieren

    推荐学习:Redis视频教程

    Das obige ist der detaillierte Inhalt vonZusammenfassung von fünf Möglichkeiten zur Implementierung verteilter Sperren in Redis. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Lösung für den Fehler 0x80242008 bei der Installation von Windows 11 10.0.22000.100 Lösung für den Fehler 0x80242008 bei der Installation von Windows 11 10.0.22000.100 May 08, 2024 pm 03:50 PM

1. Starten Sie das Menü [Start], geben Sie [cmd] ein, klicken Sie mit der rechten Maustaste auf [Eingabeaufforderung] und wählen Sie Als [Administrator] ausführen. 2. Geben Sie nacheinander die folgenden Befehle ein (kopieren und fügen Sie sie sorgfältig ein): SCconfigwuauservstart=auto, drücken Sie die Eingabetaste. SCconfigbitsstart=auto, drücken Sie die Eingabetaste. SCconfigcryptsvcstart=auto, drücken Sie die Eingabetaste. SCconfigtrustedinstallerstart=auto, drücken Sie die Eingabetaste. SCconfigwuauservtype=share, drücken Sie die Eingabetaste. netstopwuauserv, drücken Sie die Eingabetaste für netstopcryptS

Golang API-Caching-Strategie und -Optimierung Golang API-Caching-Strategie und -Optimierung May 07, 2024 pm 02:12 PM

Die Caching-Strategie in GolangAPI kann die Leistung verbessern und die Serverlast reduzieren. Häufig verwendete Strategien sind: LRU, LFU, FIFO und TTL. Zu den Optimierungstechniken gehören die Auswahl geeigneter Cache-Speicher, hierarchisches Caching, Invalidierungsmanagement sowie Überwachung und Optimierung. Im praktischen Fall wird der LRU-Cache verwendet, um die API zum Abrufen von Benutzerinformationen aus der Datenbank zu optimieren. Andernfalls kann der Cache nach dem Abrufen aus der Datenbank aktualisiert werden.

Caching-Mechanismus und Anwendungspraxis in der PHP-Entwicklung Caching-Mechanismus und Anwendungspraxis in der PHP-Entwicklung May 09, 2024 pm 01:30 PM

In der PHP-Entwicklung verbessert der Caching-Mechanismus die Leistung, indem er häufig aufgerufene Daten vorübergehend im Speicher oder auf der Festplatte speichert und so die Anzahl der Datenbankzugriffe reduziert. Zu den Cache-Typen gehören hauptsächlich Speicher-, Datei- und Datenbank-Cache. In PHP können Sie integrierte Funktionen oder Bibliotheken von Drittanbietern verwenden, um Caching zu implementieren, wie zum Beispiel Cache_get() und Memcache. Zu den gängigen praktischen Anwendungen gehören das Zwischenspeichern von Datenbankabfrageergebnissen zur Optimierung der Abfrageleistung und das Zwischenspeichern von Seitenausgaben zur Beschleunigung des Renderings. Der Caching-Mechanismus verbessert effektiv die Reaktionsgeschwindigkeit der Website, verbessert das Benutzererlebnis und reduziert die Serverlast.

So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000_So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000 So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000_So aktualisieren Sie Win11 Englisch 21996 auf vereinfachtes Chinesisch 22000 May 08, 2024 pm 05:10 PM

Zuerst müssen Sie die Systemsprache auf die Anzeige in vereinfachtem Chinesisch einstellen und neu starten. Wenn Sie die Anzeigesprache zuvor auf vereinfachtes Chinesisch geändert haben, können Sie diesen Schritt natürlich einfach überspringen. Beginnen Sie als Nächstes mit dem Betrieb der Registrierung regedit.exe, navigieren Sie direkt zu HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlNlsLanguage in der linken Navigationsleiste oder der oberen Adressleiste und ändern Sie dann den InstallLanguage-Schlüsselwert und den Standardschlüsselwert auf 0804 (wenn Sie ihn in Englisch ändern möchten). us, Sie müssen zunächst die Anzeigesprache des Systems auf en-us einstellen, das System neu starten und dann alles auf 0409 ändern) Sie müssen das System an dieser Stelle neu starten.

Wie verwende ich den Redis-Cache bei der PHP-Array-Paginierung? Wie verwende ich den Redis-Cache bei der PHP-Array-Paginierung? May 01, 2024 am 10:48 AM

Durch die Verwendung des Redis-Cache kann die Leistung des PHP-Array-Pagings erheblich optimiert werden. Dies kann durch die folgenden Schritte erreicht werden: Installieren Sie den Redis-Client. Stellen Sie eine Verbindung zum Redis-Server her. Erstellen Sie Cache-Daten und speichern Sie jede Datenseite in einem Redis-Hash mit dem Schlüssel „page:{page_number}“. Rufen Sie Daten aus dem Cache ab und vermeiden Sie teure Vorgänge auf großen Arrays.

So finden Sie die von Win11 heruntergeladene Update-Datei. Geben Sie den Speicherort der von Win11 heruntergeladenen Update-Datei an So finden Sie die von Win11 heruntergeladene Update-Datei. Geben Sie den Speicherort der von Win11 heruntergeladenen Update-Datei an May 08, 2024 am 10:34 AM

1. Doppelklicken Sie zunächst auf dem Desktop auf das Symbol [Dieser PC], um es zu öffnen. 2. Doppelklicken Sie dann mit der linken Maustaste, um [Laufwerk C] einzugeben. Systemdateien werden im Allgemeinen automatisch auf Laufwerk C gespeichert. 3. Suchen Sie dann den Ordner [Windows] auf dem Laufwerk C und doppelklicken Sie, um ihn aufzurufen. 4. Nachdem Sie den Ordner [Windows] aufgerufen haben, suchen Sie den Ordner [SoftwareDistribution]. 5. Suchen Sie nach der Eingabe den Ordner [Download], der alle Win11-Download- und Update-Dateien enthält. 6. Wenn wir diese Dateien löschen möchten, löschen Sie sie einfach direkt in diesem Ordner.

PHP-Redis-Caching-Anwendungen und Best Practices PHP-Redis-Caching-Anwendungen und Best Practices May 04, 2024 am 08:33 AM

Redis ist ein leistungsstarker Schlüsselwert-Cache. Die PHPRedis-Erweiterung stellt eine API für die Interaktion mit dem Redis-Server bereit. Führen Sie die folgenden Schritte aus, um eine Verbindung zu Redis herzustellen sowie Daten zu speichern und abzurufen: Verbinden: Verwenden Sie die Redis-Klassen, um eine Verbindung zum Server herzustellen. Speicherung: Verwenden Sie die Set-Methode, um Schlüssel-Wert-Paare festzulegen. Abrufen: Verwenden Sie die get-Methode, um den Wert des Schlüssels abzurufen.

Warum tritt bei der Installation einer Erweiterung mit PECL in einer Docker -Umgebung ein Fehler auf? Wie löst ich es? Warum tritt bei der Installation einer Erweiterung mit PECL in einer Docker -Umgebung ein Fehler auf? Wie löst ich es? Apr 01, 2025 pm 03:06 PM

Ursachen und Lösungen für Fehler Bei der Verwendung von PECL zur Installation von Erweiterungen in der Docker -Umgebung, wenn die Docker -Umgebung verwendet wird, begegnen wir häufig auf einige Kopfschmerzen ...

See all articles